Java Thread Programming 1.7-Concurrent Access to Objects and Variables

Source: Internet
Author: User
Tags secure copy
When multiple threads are interacting with an object, controls need to be in place to ensure that the threads don't adversely affect one another. this chapter deals with issues that can introduce subtle errors in your application. an application that fails to safely control concurrent access can work properly most of the time-maybe nearly all the time-but will occasionally produce erroneous results. this makes the understanding and disciplined use of the information in this chapter critical to writing truly thread-safe applications that work properly all the time. if your system encounters an inexplicable problem, it is likely to be a problem of concurrent access. Volatile Member variable Modifier  The Java Language SpecificationIndicates that for optimal speed, individual threads are permitted to keep a working copy of shared member variables and only reconcile them with the shared original occasionally. to be more accurate, the word "occasionally" in the last sentence shocould be replaced with "when a thread enters or leaves a synchronized block of code. "I'll tell you more about synchronized blocks later in this chapter. When only one thread is interacting with the member variables of an object, this optimization works very well and can allow for faster execution. when two (or more) threads are simultaneously working with an object, care must be taken to ensure that changes made to a shared member variable by one thread are seen by the other. the Java specification specifies that each thread has a copy of the shared member variable to optimize the speed. The variable value is written back only when the thread starts or ends a synchronous code block. This mechanism works well in a single thread to achieve higher performance, but when multiple threads work together, you must consider it, public variables changed by one thread should be known by other threads. The volatile keyword is used as a modifier on member variables to force individual threads to reread the variable's value from shared memory every time the variable is accessed. in addition, individual threads are forced to write changes back to shared memory as soon as they occur. this way, two different threads always see the same value for a member variable at any participant time. chances are t Hat most of you expected this behavior from the Java VM already. in fact, export experienced Java developers don't understand when the use of volatile is necessary. volatile keyword. If it is used to modify a member variable, every thread is forced to re-read the variable every time it is accessed. Every time the variable value is changed, it should be written back as soon as possible. In this way, two different threads can always obtain the same variable value at a specific time. Use volatile on member variables that can be accessed by two or more threads unless all the threads access the variables within synchronized blocks of code. if a member variable remains constant after construction (it is read-only), there is no need for it to be volatile. if a member variable is read-only, there is no need to set it to volatile. If all threads access this variable in a synchronous code block, there is no need to set it to volatile The volatile modifier exists to request that the VM always access the shared copy of the variable. this is less efficient than allowing the VM to perform optimizations by keeping a private copy. you shoshould use volatile only when it is necessary; overuse will unnecessarily slow the application's execution. volatile requires the virtual machine to return to each request for a variable, which is inefficient for maintaining a private copy for each thread and will reduce the access speed. If not necessary, do not use Synchronized Method Modifier  The addition of the synchronized modifier to a method declaration ensures that only one thread is allowed inside the method at a time. this can be useful in keeping out other threads while the state of an object is temporarily inconsistent. synchronized modifier is used to modify a method declaration, which ensures that only one thread can call this method at a time. This mechanism can prevent objects from being accessed by other threads when they are in a non-continuous state. Two threads simultaneously in the same method of one objectIf two or more threads are simultaneously inside a method, each thread has its own copy of local variables. when two or more threads call the same method of the same object at the same time, each thread has a copy of local variables.   One thread at a time More than one thread can be inside a method, and each thread keeps a copy of its own local variables. however, there are times when application constraints require that only one thread be permitted inside a method at a time.  When a thread encounters a synchronized instance method, it blocks until it can get exclusive access to the object-level mutex lock. MutexIs short for mutual exclusion. A mutex lock can be held by only one thread at a time. other threads waiting for the lock will block until it is released. when the lock is released, all the threads waiting for it compete for exclusive access. only one will be successful, and the other threads will go back into a blocked state waiting for the lock to be released again. ensure that only one thread calls a method at a time. You only need to add Sy before the method declaration. Nchronized. When a thread encounters a Method Instance declared as sychronized, it will block until it obtains access to the object-level mutex lock semaphores. The mutex signal can only be owned by one thread at a time, other threads waiting for the signal must wait for the signal to be released. After the mutex lock is released, other threads compete for access and the thread runs successfully, other threads continue to block and wait until the mutex lock is released again. Two threads, two objectsEvery instance of a class has its OwnObject-level lock. although the doStuff () method is synchronized, there is no competition for exclusive access to the object-level lock. each instance, obj1 and obj2, has its own object-level lock. when threadA enters the doStuff () method of obj1 (line 1), it acquires exclusive access to the object-level lock for obj1. When threadB enters the doStuff () method of obj2 (line 3), it acquires exclusive Access to the object-level lock for obj2. each object instance has its own object-level lock. In other words, the synchronized lock is built on the instance of the object, rather than the abstract object. When multiple threads call the same synchronized Method of the same object instance, the access is synchronized. When multiple threads call the same synchronized Method of different instances of the same object, mutual access is not mutually exclusive.   Avoiding accidental upload uption of an objectIt's an unavoidable fact that the object must be in an inconsistent state for a brief period of time, even with everything doesn't the assignments taken out: public SynchronizedVoid setNames (String firstName, String lastName ){ Fname= FirstName; Lname= Lastname;} No matter how fast the processor is, it's possible that the thread scheduld cocould swap out the thread making the changes after it has changed fname but before it has changed lname. holding an object-Level Lock does not prevent a thread from being swapped out. and if it is swapped out, it continues to hold the object-Level Lock. because of this, care must be taken to ensure that all reads are blocked when the data is in an inconsistent state. cleanread (see listing 7.16) simply adds the Synchronized Method modifier to getnames () to control concurrent reading and writing. when two threads call the method of an instance to modify some variable values at the same time, these variable values may be in non-continuous state at a certain time point. The method can be modified with synchronized to ensure the integrity of the variable values.   Deferring access to an object while it is inconsistentWhen a thread calls a synchornized Setting Value Method to modify some variable values of an instance, it only limits other threads to call this method at the same time, other threads are not restricted from calling other methods to access these variable values. If another thread calls a method that obtains the value to access these variables, some variables may have been modified, some other variables have not been modified, which may lead to non-consecutive variables. This problem can be solved by adding the synchronized modifier before the method is worthwhile. Because an object instance has only one object-Level Lock. When a synchronized method is called, other synchronized methods of this instance must wait for the lock to be released.  If two or more threads might be simultaneously interacting with the member variables of an object, and at least one of those threads might change the values, it is generally a good idea to use synchronized to control concurrent access. if only one thread will be accessing an object, using synchronized is unnecessary and slows execution. Synchronized statement BlockThe synchronized block can be used when a whole method does not need to be synchronized or when you want the thread to get an object-Level Lock on a different object. synchronized block range 1. Not all methods need to be synchronized. 2. You need to lock different objects. The synchronized statement block looks like this: Synchronized(OBJ) {// block of code} Where obj is a reference to the object whose object-Level Lock must be acquired before entering the block of code. This setpoint () methodpublic SynchronizedVoid setPoint (int x, int y) {this. x = x; this. y = y;} can be rewritten to instead use a synchronized block: public void setPoint (int x, int y ){ Synchronized(This) {this. x = x; this. y = y ;}} The behavior of both versions of setPoint () is always ally the same. they do compile to different byte-code, but both of them make sure that they have exclusive access to the object-level lock for the instance before making changes to x and y. Cing the time that the lock is heldA Synchronized block can be used to reduce the time that the object-Level Lock is held. if a method does a lot of other things that don't require access to the member variables, it can shorten the time that it holds the lock to just the critical portion: public void setvalues (int x, double ratio) {// some other, long-running statements that don't work // with the member variables go here. //... double processedvala = //... long calculation... double processedvalb = //... long calculation... //... Synchronized(This) {A = processedvala; B = processedvalb;} In setvalues (), exclusive access to the object-Level Lock is not needed until the time-consuming calculations have been made and the results are ready to be stored. at the bottom of the method, the object-Level Lock is acquired and held briefly to simply assign new values to the member variables A and B. reduce the lock time. This method only locks the location to be synchronized to minimize the lock overhead. Locking an object other than thisLock a non-this object the reference mutex indicates the object whose object-level lock must be acquired before entering the statement block. it can be a reference to any object in the VM, not just this. regardless of how a thread leaves a synchronized block, it automatically releases the lock. this includes des a return statement, a throw statement, or just falling through to the next statement after the block. calling a method from within the synchronized block does not constitute LeavingThe block (the lock is still held). It can synchronize any objects in the virtual machine, not just this. Sometimes you will need to call two synchronized methods on an object and be sure that no other thread sneaks in between the CILS. consider this code fragment from a class called Bucket: Sometimes two synchronized methods must simultaneously execute public class Bucket extends Object {//... public SynchronizedBoolean isSpaceAvailable () {//... public SynchronizedVoid add (bucketitem O) throws nospaceavailableexception {//... public SynchronizedBucketItem remove (){//... //...} A call method: Bucket B = //... //... if (B. isSpaceAvailable () {B. add (item);} This is fine if only one thread is interacting with this instance of Bucket. but if multiple threads are potentially trying to add BucketItem objects to the same Bucket, a new approach has to be taken to avoid a race condition. imagine that threadA checks and sees that space is available, but before it actually adds its item, threadB checks and also sees that space is available. now threadA and threadB are racing to actually add an item. only one can win the race, and that thread gets to add its item. the other thread will fail to add its item and will throw a NoSpaceAvailableException. to prevent this problem, a synchronized block shoshould be wrapped around the two method CALS: this method is correct when only one thread exists. Otherwise, a synchronization error occurs. Bucket B = //... //... Synchronized (B ){If (B. isSpaceAvailable () {B. add (item) ;}} The synchronized block uses the object-level lock on B, the Bucket instance. this is the same lock that must be acquired before entering the isSpaceAvailable () and add () methods. if a thread can get the object-level lock and enter the synchronized block, it is guaranteed to be able to invoke isSpaceAvailable () and add () without blocking. because it already has the object-level lock for B, there is no delay or competition to enter the synchronized methods. in addition, no other thread can invoke these methods until the first thread leaves the synchronized block. when this code is placed in a block, other threads cannot call any synchronized Method in B. Once a thread acquires a block, it is bound to be able to execute the code in the lock without competition from other threads. Static synchronized methods  In addition to Object-Level lock that exists for each instance of a class, there is Class-Level lock that all instances of a particle class share. Every class loaded by the VM has exactly one Class-Level Lock. If a method is both static and synchronized, a thread must get exclusive access to the class-level lock before entering the method. the class-level lock can be used to control concurrent access to static member variables. just as the object-level lock was needed to prevent data upload uption in non-static member variables, the class-level lock is needed to prevent upload uption of static member variables. even when no variables are involved, the synchronized modifier can be used on static methods simply to ensure that only one thread is inside the method at a time.   Object-Level lock corresponds to each instance of the class. Class-Level lock corresponds to all instances of the class, and each class generated by the virtual machine has Class-Level lock: For a static synchronized method, the thread excludes access before calling this method. Class-Level lock. Using the class-Level Lock in a synchronized statement  The synchronized statement can also use a class-Level Lock. this can be useful if a static method runs for a long period of time. additionally, it can be used to ensure that two static method callby one thread are not interleaved with a call by another thread. to lock on the class-Level Lock, use the following codesynchronized (classname. Class) {// Body}  Use class-Level Lock to synchronize code blocks, and use synchronized (class name. Class ){} Synchronization and the collections API  Vector and Hashtable were originally designed to be multithread-safe. take Vector, for example-the methods used to add and remove elements are synchronized. if only one thread will ever interact with an instance of Vector, the work required to acquire and release the object-level lock is wasted. vector and Hashtable are initially designed to be thread-safe. Most of their methods are synchronized, this is unnecessary in a single-threaded program. The designers of the Collections API wanted to avoid the overhead of synchronization when it wasn' t necessary. as a result, none of the methods that alter the contents of a collection are synchronized. if a Collection or Map will be accessed by multiple threads, it shoshould be wrapped by a class that synchronizes all the methods. collections are not inherently multithread-safe. extra steps must be taken when more than one thread will be interacting with a collection to make it multithread-safe. the Collection API is designed to be synchronized when needed. By default, it is not thread-safe. If you use Collection in a multi-threaded environment, first, convert it to thread-safe There are several static methods in the Collections class that are used to wrap unsynchronized collections with synchronized methods: public static Collection Synchronizedcollection(Collection C) public static list Synchronizedlist(List l) Public static Map Synchronizedmap(MAP m) public static set SynchronizedSet(Set S) public static sortedmap SynchronizedSortedMap(Sortedmap sm) public static sortedset SynchronizedSortedSet(SortedSet ss) the collection class provides several static methods to convert a non-thread-safe set to a thread-safe set. The preceding method is used as follows: Basically, these methods return new classes that have synchronized versions of the collections 'Methods. to create a List that is multithread-safe and backed by an ArrayList, use the following: List list = Collections. synchronizedList (new ArrayList (); When synchronizing collections, do not keep any direct reference to the original unsynchroni Zed collection. This will ensure that no other thread accidentally makes uncoordinated changes. To ensure collection synchronization, do not directly use the originally non-thread-safe set. Safely Copying the Contents of a List into an ArrayThree methods: secure copy List as an array   Safely Iterating Through the Elements of a CollectionThe element of a Collection can be stepped through one by using an Iterator. in a multithreaded environment, you will generally want to block other threads from adding or removing elements while you are iterating through the current collection of elements.   Deadlocks  Using locks to control concurrent access to data is critical to avoid subtle race conditions within applications. however, trouble can arise when a thread needs to hold more than one lock at a time. the lock mechanism is used to control concurrent access to key data. When a thread has more than two locks at the same time, the deadlock Deadlocks can be extremely difficult to track down. generally, most of an application will continue to run, but a couple of threads will be stuck in a deadlock. to make matters worse, deadlocks can hide in code for quite a while, waiting for a rare condition to occur. an application can run fine 99 out of 100 times and only deadlock when the thread scheduler happens to run the threads in a slightly different order. deadlock avoidance is a difficult task.  Most code is not vulnerable to deadlocks, but for the code that is, try following these guidelines to help avoid deadlocks: l Hold locks for only the minimal amount of time necessary. consider using synchronized statement blocks instead of synchronizing the whole method. l Try to write code that does not need to hold more than one lock at a time. if this is unavoidable, try to make sure that threads hold the second lock only for a brief period of time. l Create and use one BigLock instead of several small ones. use this lock for mutual exclusion instead of the object-level locks of the individual objects. l check out the interruptiblesyncblock class in chapter 17. it uses another object to control concurrent access to a section of code. additionally, instead of having a thread block on the synchronized statement, the thread is put into a wait-state that IsInterruptible. I'll tell you more about of the wait-your y mechanic in Chapter 8. Deadlock is hard to avoid. Generally, there are the following principles to reduce the possibility of deadlock l lock as short as possible, try to use synchronized statement instead of using synchronized entire method l try not to have more than one lock at the same time, if this is unavoidable, make sure that the thread holds the second lock for as short as possible. l create a large lock instead of multiple small locks, the InterruptibleSyncBlock class is given in chapter 17 of the small lock on each object with a new large lock. It uses another object to control concurrent access to the code block. Do not block a thread when synchronizing a statement, but put it in an interrupted wait state. Use the wait-policy mechanism discussed in the next chapter.   Speeding Concurrent Access  To speed up execution, do not use synchronized unnecessarily. be sure that it's really needed for proper functioning. if synchronization is necessary, see if using a synchronized statement block wocould work instead of a synchronized method. although this won't decrease the cost of acquiring and releasing the lock, it will reduce contention for the lock among the other threads because the lock is held for a shorter period of time. methods To accelerate synchronous access: 1. If not necessary, synchronized2 is not applicable. If synchronized statement block is used, synchronized method is not used, which reduces the probability of conflict. Summary  In this chapter, I showed you: l how to use VolatileTo force unsynchronized threads to work with the shared copy of a variable instead of a private working copy. l how to use Synchronized MethodModifier on non-static methods to require a thread to get exclusive access to the object-level lock before entering the method. l How to use Synchronized Statement blockTo require a thread to get exclusive access to the object-level lock of the specified object before executing the code within the block. l How to use Synchronized Method modifier on Static MethodsTo require a thread to get exclusive access to the class-level lock before entering the method. l How to work Safely with the Collections APIIn a multithreaded environment. l How to understand the causes Deadlocks, And how to try to avoid them. the volatile modifier ensures that the synchronization of multi-threaded variables uses the synchronized modifier to ensure that an object instance uses the synchronized Modifier on the object-Level Lock to ensure that the object static method is synchronized to the class-Level Lock ensure thread security using collection classes, first, you must convert the collection class to generate a thread-safe collection class.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.