Java Thread (ii): Thread synchronization synchronized and volatile

Source: Internet
Author: User
Tags volatile

In the previous article, a simple example shows that thread safety and insecurity, in the case of unsafe conditions, the output is exactly incremental (in fact, it is a coincidence, run more than a few times, will produce different output results), why this result is generated, because the build Count object is thread-shared, A thread changes the NUM value of its member variable, and the next thread happens to read the modified num, so it increments the output.

To illustrate the thread synchronization problem, first describe the two features, visibility, and ordering of Java threads. There is no direct data interaction between multiple threads, and the interaction between them can only be achieved through shared variables. Take the example from the blog post to show that an object of the Count class is shared among multiple threads, that the object is created in main memory (heap memory), each thread has its own working memory (line stacks), the working memory stores a copy of the main memory count object, and when the thread is manipulating the Count object, The Count object is first copied from main memory into working memory, then code Count.count () is executed, the NUM value is changed, and finally the main memory count is flushed with the working memory count. When an object has replicas in more than one memory, if one memory modifies the shared variable, the other thread should be able to see the modified value, which is the visibility . When multiple threads are executing, the CPU is randomly scheduling the thread, and we do not know which step the current program is executed to switch to the next thread, one of the most classic examples is the bank transfer problem, a bank account deposit 100, then a person from the account to take 10 yuan, while another person to the account remitted 10 yuan, Then the balance should still be 100. So this can happen at this time, a thread responsible for withdrawals, B thread responsible for remittances, a from the main memory read to 100,b from the main memory read to 100,a perform minus 10 operations, and the data flushed to the main memory, when the main memory data 100-10=90, and B memory execution plus 10 operation, and the data flushed to the main memory , the final main memory data 100+10=110, obviously this is a serious problem, we want to ensure that a thread and B thread in order to execute, the first withdrawal after the remittance or the first remittance after the withdrawal, this is ordered . This article describes how traditional threads are synchronized prior to JDK5.0, and more advanced synchronization methods are available in Java Threads (eight): Lock object lock-synchronization problem is a more perfect way to handle it.

The following code is also used to illustrate a thread synchronization problem.

Traditionalthreadsynchronized.java: Creates two threads and executes the output method of the same object.

[Java]View PlainCopyprint?
  1. Public class Traditionalthreadsynchronized {
  2. public static void Main (string[] args) {
  3. final Outputter output = new Outputter ();
  4. New Thread () {
  5. public Void Run () {
  6. Output.output ("Zhangsan");
  7. }
  8. }.start ();
  9. New Thread () {
  10. public Void Run () {
  11. Output.output ("Lisi");
  12. }
  13. }.start ();
  14. }
  15. }
  16. Class Outputter {
  17. public void output (String name) {
  18. //TODO to ensure that the output to name is not an atomic operation, each character of name is output here individually
  19. For (int i = 0; i < name.length (); i++) {
  20. System.out.print (Name.charat (i));
  21. //Thread.Sleep (10);
  22. }
  23. }
  24. }

Operation Result:

[Java]View PlainCopyprint?
    1. Zhlainsigsan

Obviously the output string is scrambled, we expect the output to be zhangsanlisi, this is the thread synchronization problem, we want the output method to be completed by a thread after the execution of the next thread, Using synchronized in Java guarantees that a piece of code is mutually exclusive when multithreaded execution, and there are two ways to use it:

1. Use synchronized to include the code that requires mutual exclusion, and a lock on it.

[Java]View PlainCopyprint?
    1. {
    2. synchronized (this) {
    3. For (int i = 0; i < name.length (); i++) {
    4. System.out.print (Name.charat (i));
    5. }
    6. }
    7. }

This lock must be a shared object between multiple threads that need to be mutually exclusive, as the following code is meaningless.

[Java]View PlainCopyprint?
    1. {
    2. Object lock = new Object ();
    3. synchronized (lock) {
    4. For (int i = 0; i < name.length (); i++) {
    5. System.out.print (Name.charat (i));
    6. }
    7. }
    8. }

Each time you enter the output method, a new lock is created, and it is clear that each thread will be created with no meaning.

2. Add the synchronized to the method that requires mutual exclusion.

[Java]View PlainCopyprint?
    1. Public synchronized void output (String name) {
    2. //TODO thread output method
    3. For (int i = 0; i < name.length (); i++) {
    4. System.out.print (Name.charat (i));
    5. }
    6. }

This is equivalent to locking the code block in the entire method with this, and if synchronized is added to the static method, it is equivalent to locking the block of code in the entire method with Xxxx.class. Using synchronized can cause deadlocks in some cases, and the deadlock problem will be explained later. a method or block of code that uses synchronized adornments can be seen as an atomic operation .

Each lock pair (called Monitor in JLS) has two queues, one is a ready queue, one is a blocking queue, the ready queue stores the thread that will acquire the lock, the blocking queue stores the blocked thread, and when a thread is awakened (notify), it goes into the ready queue, waits for the CPU to dispatch, and vice versa. , when a thread is waiting, it enters the blocking queue and waits for the next wake-up, which involves the communication between threads, which is explained in the next post. Looking at our example, when the first thread executes the output method, it obtains a synchronous lock, executes the output method, exactly at this point the second thread also executes the output method, but discovers that the synchronization lock is not released, the second thread enters the ready queue, waits for the lock to be released. One thread executes the mutex code procedure as follows:

1. Obtain the synchronous lock;

2. Clear the working memory;

3. Copy the object from the main memory to the working memory;

4. Execute the code (calculation or output, etc.);

5. Refresh the main memory data;

6. Release the sync lock.

Therefore, synchronized not only guarantees the concurrent order of multithreading, but also ensures the memory visibility of multithreading.

Volatile is the second Java multithreading mechanism, according to JLS (Java languagespecifications), a variable can be modified by volatile, in which case the memory model (main memory and thread working memory) Make sure that all threads can see a consistent variable value and take a look at the code:

[Java]View PlainCopyprint?
  1. Class Test {
  2. static int i = 0, j = 0;
  3. static void One () {
  4. i++;
  5. j + +;
  6. }
  7. static void () {
  8. System.out.println ("i=" + i + "j=" + j);
  9. }
  10. }

Some threads execute the one method, while others execute the two methods, and it is possible to print out a value of J greater than I did in the previously analyzed thread execution process:

1. Copy the variable i from the main memory to the working memory;

2. Change the value of I;

3. Refresh the main memory data;

4. Copy the variable J from the main memory to the working memory;

5. Change the value of J;

6. Refresh the main memory data;

This time the thread that executes the two methods reads the original value of main memory I and reads the value of J changed, which leads to the output of the program is not the result we expected, one way to stop this irrational behavior is to precede the single method and the two methods with the synchronized modifier:

[Java]View PlainCopyprint?
  1. Class Test {
  2. static int i = 0, j = 0;
  3. static synchronized void One () {
  4. i++;
  5. j + +;
  6. }
  7. static synchronized void () {
  8. System.out.println ("i=" + i + "j=" + j);
  9. }
  10. }

According to the previous analysis, we can know that at this point the one method and the method are no longer executed concurrently, the values of I and J will remain consistent in the main memory, and the output of the same method is consistent. Another mechanism for synchronization is to add volatile before sharing a variable:

[Java]View PlainCopyprint?
  1. Class Test {
  2. static volatile int i = 0, j = 0;
  3. static void One () {
  4. i++;
  5. j + +;
  6. }
  7. static void () {
  8. System.out.println ("i=" + i + "j=" + j);
  9. }
  10. }

The one and the other methods are also executed concurrently, but with volatile you can directly respond to the changes in the shared variables I and J to main memory, thus guaranteeing the consistency of the values of I and J in main memory , but when executing the At the time when the two method obtains the value of I and gets to the value of J, the one method may have been executed several times, causing the value of J to be greater than the value of I. Therefore, volatile can guarantee the memory visibility, and can not guarantee the concurrency of order.

It's not good to understand why JLS uses two variables to illustrate how volatile works. Volatile is a weak synchronization means, in some cases, with respect to synchronized, may be more efficient, because it is not blocking, especially when reading operations, plus and without seeming to have no effect, when processing write operations, may consume more performance. But volatile and synchronized performance comparison, I also say that is not very accurate, multithreading itself is more Xuan, relying on the CPU time shard scheduling, JVM More Xuan, has not studied virtual machine, from the top floor to the bottom of the view is often difficult to see through. Before JDK5.0, if you do not have a volatile use of the scene, or do not use, as far as possible to use synchronized to deal with synchronization problems, thread blocking this thing simple and rude. In addition, volatile and final cannot modify a field at the same time , you can think about why.

This article from: Gao | Coder, original address: http://blog.csdn.net/ghsau/article/details/7424694

Java Thread (ii): Thread synchronization synchronized and volatile

Related Article

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.