Java thread (2): synchronized and volatile

Source: Internet
Author: User

To illustrate the thread synchronization problem, we must first describe the two features of Java threads, visibility and orderliness. Data Interaction cannot be directly transmitted between multiple threads. Interaction between threads can only be achieved through shared variables. The example in the previous blog shows that an object of the Count class is shared among multiple threads. This object is created in the main memory (heap memory, each thread has its own working memory (thread stack). The working memory stores a copy of the master memory Count object. When the thread operates the Count object, first, copy the Count object from the primary memory to the working memory, and then execute the code count. count (), changed the num value, and finally refreshed the master memory Count with the working memory Count. When an object has copies in multiple memories, if one memory modifies the shared variable, other threads should be able to see the modified value, which is visibility. As we can see from the above, a value assignment operation is not an atomic operation. When multiple threads are executed, the CPU schedules threads randomly, we do not know where the current program is executed and switch to the next thread. The most typical example is the bank remittance problem. A bank account has a deposit of 100, at this time, a person will get 10 yuan from the account, and another person will remit 10 yuan to the account, then the balance should be 100. This may happen at this time. Thread A is responsible for withdrawal, thread B is responsible for remittance, and thread A reads 100 from the outbound memory. Thread B reads 100 from the primary memory, and A performs 10 minus operations, and refresh the data to the main memory. In this case, the data in the main memory is 100-10 = 90, while in the B memory, the data is refreshed to the main memory, and the data in the main memory is 100 + 10 = 110, obviously, this is A serious problem. We need to ensure that thread A and thread B are executed in an orderly manner. This is an order to make money after withdrawal or after remittance.
The following code also shows the thread synchronization problem.
TraditionalThreadSynchronized. java: creates two threads and executes the output method of the same object.
[Java]
Public class TraditionalThreadSynchronized {
Public static void main (String [] args ){
Final Outputter output = new Outputter ();
New Thread (){
Public void run (){
Output. output ("zhangsan ");
};
}. Start ();
New Thread (){
Public void run (){
Output. output ("lisi ");
};
}. Start ();
}
}
Class Outputter {
Public void output (String name ){
// TODO to ensure that the output of name is not an atomic operation, each character of name is output one by one.
For (int I = 0; I <name. length (); I ++ ){
System. out. print (name. charAt (I ));
}
}
}
Running result:
[Java]
Zhlainsigsan
Obviously, the output string is messy. We expect the output result to be zhangsanlisi, which is a thread synchronization problem. We hope that the output method will be switched to the next thread after being fully executed by a thread, in Java, synchronized is used to ensure that a piece of code is mutually exclusive during multi-thread execution. There are two usage methods:
1. Use synchronized to include the code that requires mutual exclusion and apply a lock.
[Java]
Synchronized (this ){
For (int I = 0; I <name. length (); I ++ ){
System. out. print (name. charAt (I ));
}
}
This lock must be a shared object between threads, and the following code is meaningless.
[Java]
Object lock = new Object ();
Synchronized (lock ){
For (int I = 0; I <name. length (); I ++ ){
System. out. print (name. charAt (I ));
}
}
Each time you enter the output method, a new lock will be created. This lock is obviously created by every thread and does not make sense.
2. Add synchronized to the method that requires mutual exclusion.
[Java]
Public synchronized void output (String name ){
// TODO thread output method
For (int I = 0; I <name. length (); I ++ ){
System. out. print (name. charAt (I ));
}
}
This method is equivalent to locking the code block in the entire method with this. If synchronized is used in the static method, it is equivalent to locking the code block in the entire method with ××××. class. Synchronized may cause deadlocks in some cases. The deadlock issue will be explained later.
Each lock object has two queues: one is a ready queue and the other is a blocking queue. The ready queue stores the thread to obtain the lock, and the blocking queue stores the blocked thread, when a thread is awakened, it enters the ready queue and waits for CPU scheduling. On the contrary, when a thread is wait, it enters the blocked queue, wait for the next wake-up request, which involves inter-thread communication, as described in the next blog. Let's look at our example. When a local thread executes the output method, it obtains the synchronization lock and executes the output method. At this time, the second thread also needs to execute the output method, but it finds that the synchronization lock has not been released, the second thread enters the ready queue, waiting for the lock to be released. The mutex code execution process of a thread is as follows:
1. Get the synchronization lock;
2. Clear the working memory;
3. Copy object copies from the primary memory to the working memory;
4. Execute the code (computing or output );
5. Refresh master memory data;
6. Release the synchronization lock.
Therefore, synchronized not only ensures the concurrency orderliness of multiple threads, but also ensures the memory visibility of multiple threads.
Volatile is the second method of Java multi-thread synchronization. According to JLS, a variable can be modified by volatile. In this case, the memory model ensures that all threads can see consistent variable values, let's look at a piece of code:
[Java]
Class Test {
Static int I = 0, j = 0;
Static void one (){
I ++;
J ++;
}
Static void two (){
System. out. println ("I =" + I + "j =" + j );
}
}
Some threads execute the one method and some other threads execute the two method. The two method may print j values greater than I. Analyze the thread execution process as analyzed previously:
1. Copy variable I from main memory to working memory;
2. Change the I value;
3. Refresh master memory data;
4. Copy the variable j from the primary memory to the working memory;
5. Change the j value;
6. Refresh master memory data;
At this time, the thread executing the two method first reads the original value of primary memory I and then the value changed by j, which leads to program output not as expected, you can add volatile before the shared variable.
[Java]
Class Test {
Static volatile int I = 0, j = 0;
Static void one (){
I ++;
J ++;
}
Static void two (){
System. out. println ("I =" + I + "j =" + j );
}
}
With volatile, the changes of shared variables I and j can be directly returned to the primary memory, which ensures that the values of I and j can be consistent, however, we cannot guarantee the degree to which the thread that executes the two method is obtained during I and j execution. Therefore, volatile can ensure memory visibility and cannot guarantee concurrency orderliness.

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.