Java concurrent programming: Synchronized and its implementation principle.

Source: Internet
Author: User

Java concurrent programming: Synchronized and its implementation principle.

Java concurrent programming series [unfinished ]:

Java concurrent programming: core Theory

Java concurrent programming: Synchronized and its implementation principle

 

I. basic use of Synchronized

Synchronized is the most common method to solve the concurrency problem in Java and the simplest method. Synchronized has three main functions: (1) ensure mutually exclusive access to the synchronization code (2) ensure that the modification of shared variables can be visible in a timely manner (3) effectively solves the re-sorting problem. Synchronized has three Synchronized usage methods:

(1) modifying common methods

(2) Static modification method

(3) modify the code block

Next, I will use several examples to illustrate these three usage methods (to facilitate comparison, the three pieces of code are basically consistent except for Synchronized usage ).

1. No synchronization:

Code snippet 1:

 1 package com.paddx.test.concurrent; 2  3 public class SynchronizedTest { 4     public void method1(){ 5         System.out.println("Method 1 start"); 6         try { 7             System.out.println("Method 1 execute"); 8             Thread.sleep(3000); 9         } catch (InterruptedException e) {10             e.printStackTrace();11         }12         System.out.println("Method 1 end");13     }14 15     public void method2(){16         System.out.println("Method 2 start");17         try {18             System.out.println("Method 2 execute");19             Thread.sleep(1000);20         } catch (InterruptedException e) {21             e.printStackTrace();22         }23         System.out.println("Method 2 end");24     }25 26     public static void main(String[] args) {27         final SynchronizedTest test = new SynchronizedTest();28 29         new Thread(new Runnable() {30             @Override31             public void run() {32                 test.method1();33             }34         }).start();35 36         new Thread(new Runnable() {37             @Override38             public void run() {39                 test.method2();40             }41         }).start();42     }43 }

The execution result is as follows: thread 1 and thread 2 enter the execution state at the same time. Thread 2 is faster than thread 1, so thread 2 is executed first, in this process, thread 1 and thread 2 are executed simultaneously.

Method 1 startMethod 1 executeMethod 2 startMethod 2 executeMethod 2 endMethod 1 end

2. Synchronization of common methods:

Code Segment 2:

 1 package com.paddx.test.concurrent; 2  3 public class SynchronizedTest { 4     public synchronized void method1(){ 5         System.out.println("Method 1 start"); 6         try { 7             System.out.println("Method 1 execute"); 8             Thread.sleep(3000); 9         } catch (InterruptedException e) {10             e.printStackTrace();11         }12         System.out.println("Method 1 end");13     }14 15     public synchronized void method2(){16         System.out.println("Method 2 start");17         try {18             System.out.println("Method 2 execute");19             Thread.sleep(1000);20         } catch (InterruptedException e) {21             e.printStackTrace();22         }23         System.out.println("Method 2 end");24     }25 26     public static void main(String[] args) {27         final SynchronizedTest test = new SynchronizedTest();28 29         new Thread(new Runnable() {30             @Override31             public void run() {32                 test.method1();33             }34         }).start();35 36         new Thread(new Runnable() {37             @Override38             public void run() {39                 test.method2();40             }41         }).start();42     }43 }

The execution result is as follows. Compared with code snippet 1, we can see that thread 2 can start executing the method2 method only after the execution of method1 in thread 1 is complete.

Method 1 startMethod 1 executeMethod 1 endMethod 2 startMethod 2 executeMethod 2 end

3. Static Method (class) Synchronization

Code snippet 3:

 1 package com.paddx.test.concurrent; 2   3  public class SynchronizedTest { 4      public static synchronized void method1(){ 5          System.out.println("Method 1 start"); 6          try { 7              System.out.println("Method 1 execute"); 8              Thread.sleep(3000); 9          } catch (InterruptedException e) {10              e.printStackTrace();11          }12          System.out.println("Method 1 end");13      }14  15      public static synchronized void method2(){16          System.out.println("Method 2 start");17          try {18              System.out.println("Method 2 execute");19              Thread.sleep(1000);20          } catch (InterruptedException e) {21              e.printStackTrace();22          }23          System.out.println("Method 2 end");24      }25  26      public static void main(String[] args) {27          final SynchronizedTest test = new SynchronizedTest();28          final SynchronizedTest test2 = new SynchronizedTest();29  30          new Thread(new Runnable() {31              @Override32              public void run() {33                  test.method1();34              }35          }).start();36  37          new Thread(new Runnable() {38              @Override39              public void run() {40                  test2.method2();41              }42          }).start();43      }44  }

The execution result is as follows. Synchronization of static methods is essentially synchronization of classes (static methods are essentially class methods, not methods on objects ), so even if test and test2 belong to different objects, they all belong to the instance of the SynchronizedTest class, so they can only be executed in sequence method1 and method2, and cannot be executed concurrently.

Method 1 startMethod 1 executeMethod 1 endMethod 2 startMethod 2 executeMethod 2 end

4. code block Synchronization

Code segment 4:

 1 package com.paddx.test.concurrent; 2  3 public class SynchronizedTest { 4     public void method1(){ 5         System.out.println("Method 1 start"); 6         try { 7             synchronized (this) { 8                 System.out.println("Method 1 execute"); 9                 Thread.sleep(3000);10             }11         } catch (InterruptedException e) {12             e.printStackTrace();13         }14         System.out.println("Method 1 end");15     }16 17     public void method2(){18         System.out.println("Method 2 start");19         try {20             synchronized (this) {21                 System.out.println("Method 2 execute");22                 Thread.sleep(1000);23             }24         } catch (InterruptedException e) {25             e.printStackTrace();26         }27         System.out.println("Method 2 end");28     }29 30     public static void main(String[] args) {31         final SynchronizedTest test = new SynchronizedTest();32 33         new Thread(new Runnable() {34             @Override35             public void run() {36                 test.method1();37             }38         }).start();39 40         new Thread(new Runnable() {41             @Override42             public void run() {43                 test.method2();44             }45         }).start();46     }47 }

The execution result is as follows. Although both thread 1 and thread 2 enter the corresponding method to start execution, before thread 2 enters the synchronization block, it must wait until the synchronization block in thread 1 is completed.

Method 1 startMethod 1 executeMethod 2 startMethod 1 endMethod 2 executeMethod 2 end

Ii. Synchronized Principle

If you have any questions about the above execution results, you don't have to worry about it. Let's first understand the principles of Synchronized, and then let's look back at the above questions. Let's first decompile the following code to see how Synchronized synchronizes the code block:

1 package com.paddx.test.concurrent;2 3 public class SynchronizedDemo {4     public void method() {5         synchronized (this) {6             System.out.println("Method 1 start");7         }8     }9 }

Decompilation result:

Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows:
• If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor.
• If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.
• If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to gain ownership.

The general meaning of this passage is:

Each object has a monitor lock ). When the monitor is occupied, it is locked. When the thread executes the monitorenter command, it tries to obtain the monitor ownership. The process is as follows:

1. If the number of inputs to monitor is 0, the thread enters monitor and sets the number of inputs to 1, which is the monitor owner.

2. If the thread already occupies the monitor, it only enters the monitor entry shujia 1.

3. If other threads already occupy the monitor, the thread will be blocked until the number of monitor entries is 0 and the monitor ownership will be obtained again.

Monitorexit:

The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.
The thread decrements the entry count of the monitor associated with objectref. if as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. other threads that are blocking to enter the monitor are allowed to attempt to do so.

The general meaning of this passage is:

The thread that executes monitorexit must be the owner of the monitor corresponding to objectref.

When the command is executed, the number of inputs to monitor is reduced by 1. If the number of inputs to monitor is reduced by 0, the thread exits from monitor and is no longer the owner of the monitor. Other threads blocked by the monitor can try to obtain the ownership of the monitor.

Through the two descriptions, we should be able to clearly see the implementation principle of Synchronized. The underlying semantics of Synchronized is achieved through a monitor object, in fact, wait/notify and other methods also depend on the monitor object. This is why wait/notify and other methods can be called only in the synchronized block or method. Otherwise, java will be thrown. lang. the cause of the IllegalMonitorStateException.

Let's take a look at the decompilation results of the synchronization method:

Source code:

1 package com.paddx.test.concurrent;2 3 public class SynchronizedMethod {4     public synchronized void method() {5         System.out.println("Hello World!");6     }7 }

Decompilation result:

Iii. Explanation of running results

With the understanding of the Synchronized principle, let's take a look at the above program.

1. Result of code Segment 2:

Although method1 and method2 are different methods, both methods are synchronized and called through the same object, therefore, we need to compete for the lock (monitor) on the same object before the call, so we can only obtain the lock mutex. Therefore, method1 and method2 can only be executed in sequence.

2. Result of code Segment 3:

Although test and test2 belong to different objects, test and test2 belong to different instances of the same class. Because both method1 and method2 belong to static Synchronization Methods, therefore, you need to obtain the monitor on the same class (each class corresponds to only one class Object) during the call, so you can only execute it in sequence.

3. Result of code segment 4:

For code block synchronization, You need to obtain the monitor of the object in the brackets following the Synchronized keyword. Because the content in the brackets in this code is this, method1 and method2 are called through the same object, therefore, before entering the synchronization block, you need to compete for the lock on the same object. Therefore, you can only execute the synchronization block in sequence.

Iv. Summary

Synchronized is the most commonly used method for Java concurrent programming to ensure thread security. It is relatively simple to use. However, if you have a deep understanding of the principle and the underlying knowledge of the monitor lock, on the one hand, it can help us to correctly use the Synchronized keyword, and on the other hand, it can help us better understand the concurrent programming mechanism, this helps us to select a better concurrency policy to complete tasks under different circumstances. You can easily cope with various concurrency problems.

 

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.