Synchronized is one of the most common methods for solving concurrency problems in Java, and is the simplest one. There are three main functions of synchronized: (1) ensure thread-mutually exclusive access synchronization code (2) Ensure that changes to shared variables are visible in time (3) to resolve reordering issues effectively. Syntactically speaking, there are three ways to use synchronized:
(1) General method of modification
(2) Modifying the static method
(3) Modifier code block
First look at the situation where synchronization is not used
Public classSynchronizedtest { Public voidmethod1 () {System.out.println ("Method1 Start"); Try{System.out.println ("Method1 Excute"); Thread.Sleep (3000); }Catch(Exception e) {e.printstacktrace (); } System.out.println ("Method1 End"); } Public voidmethod2 () {System.out.println ("Method2 Start"); Try{System.out.println ("Method2 Excute"); Thread.Sleep (1000); }Catch(Exception e) {e.printstacktrace (); } System.out.println ("Method2 End"); } Public Static voidMain (string[] args) {FinalSynchronizedtest test=Newsynchronizedtest (); NewThread (NewRunnable () {@Override Public voidrun () {test.method1 (); }}). Start (); NewThread (NewRunnable () {@Override Public voidrun () {test.method2 (); }}). Start (); }}
The output is: (thread 1 and thread 2 go into the execution state at the same time, thread 2 executes faster than thread 1, so thread 2 executes first, and threads 1 and thread 2 are executed concurrently.) )
Method1 start
Method1 Excute
METHOD2 start
METHOD2 Excute
Method2 End
Method1 End
Use synchronized to modify the normal method, the other remains unchanged, the output result is
Method1 start
Method1 Excute
Method1 End
METHOD2 start
METHOD2 Excute
Method2 End
It is clear that thread 2 needs to wait for thread 1 's method1 execution to finish before it can begin executing the METHOD2 method. Why? Because the Synchronized keyword decoration method is used, the lock is this, which is the instance test of the class that called method.
If one is added to the main method
Final synchronizedtest test1=new synchronizedtest ();
and using Test1 to call METHOD2, the output is as follows:
Method1 start
Method1 Excute
METHOD2 start
METHOD2 Excute
Method2 End
Method1 End
Why? Because although the keyword synchronized is used, the object that calls synchronized is inconsistent, that is, synchronized locks are not the same object, so synchronization does not take effect.
Use the Synchronize to modify the static method (the method is modified to static synchronized, others are unchanged), and the output is
Method1 start
Method1 Excute
Method1 End
METHOD2 start
METHOD2 Excute
Method2 End
Can be seen as sequential execution
If one is added to the main method
Final synchronizedtest test1=new synchronizedtest ();
and using Test1 to call METHOD2, the output is consistent, why?
Synchronization of static methods is essentially a synchronization of classes (static methods are essentially methods of classes, not methods on objects), so even though Test and test2 belong to different objects, they all belong to instances of the Synchronizedtest class. So also can only execute method1 and method2 sequentially, cannot execute concurrently.
Decorating code blocks with synchronized
Public classSynchronizedtest { Public voidmethod1 () {System.out.println ("Method1 Start"); Try{ synchronized( This) {System.out.println ("Method1 Excute"); Thread.Sleep (3000); } }Catch(Exception e) {e.printstacktrace (); } System.out.println ("Method1 End"); } Public voidmethod2 () {System.out.println ("Method2 Start"); Try{ synchronized( This) {System.out.println ("Method2 Excute"); Thread.Sleep (1000); } }Catch(Exception e) {e.printstacktrace (); } System.out.println ("Method2 End"); } Public Static voidMain (string[] args) {FinalSynchronizedtest test=Newsynchronizedtest ();//final synchronizedtest test1=new synchronizedtest (); NewThread (NewRunnable () {@Override Public voidrun () {test.method1 (); }}). Start (); NewThread (NewRunnable () {@Override Public voidrun () {test.method2 (); }}). Start (); }}
The output is:
Method1 start
Method1 Excute
METHOD2 start
Method1 End
METHOD2 Excute
Method2 End
You can see that the results are executed in a non-sequential, why?
This involves the principle of the Synchronized keyword.
Look at the synchronized code block first, the code first JAVAC programming, and then the javap-c to decompile the results are as follows:
For the purpose of these two directives, we refer directly to the JVM specification:
Monitorenter:
Each object was associated with a monitor. A Monitor is locked if and only if it have 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 are zero, the thread enters the monitor and sets its entry Coun T 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, and 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 approximate meaning of this passage is:
Each object has a monitor lock. When monitor is occupied, it is locked, and the thread attempts to take ownership of the monitor while executing the monitorenter instruction, as follows:
1. If the monitor has an entry number of 0, the thread enters monitor and then sets the entry number to 1, which is the owner of the Monitor.
2, if the thread already occupies the monitor, just re-enter, then enter the monitor into the number plus 1.
3. If another thread has already occupied monitor, the thread goes into a blocking state until the number of incoming monitor is 0, and then tries to get ownership of monitor again.
Monitorexit:
The thread that executes Monitorexit must is 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 are no longer its owner. Other threads, that is blocking to enter the monitor is allowed to attempt.
The approximate meaning of this passage is:
The thread executing the monitorexit must be the owner of the monitor that corresponds to ObjectRef.
When the instruction is executed, the monitor enters the number minus 1, and if the number is 0 after minus 1, the thread exits monitor and is no longer the owner of the Monitor. Other threads that are blocked by this monitor can try to get ownership of the monitor.
Through these two paragraphs, we should be able to clearly see the implementation of the principle of synchronized, synchronized semantic bottom is through a monitor object to complete, in fact, wait/notify and other methods are also dependent on the monitor object, This is why it is only possible to call wait/notify and other methods in a synchronized block or method, or else the cause of the java.lang.IllegalMonitorStateException exception will be thrown.
Then look at the synchronized synchronization method:
The Synchronized method Controls access to class member variables: Each class instance corresponds to a lock, and each synchronized method must obtain a lock on the class instance that invokes the method to
execution, otherwise the owning thread is blocked, and once the method executes, the lock is exclusive until the lock is released when the method returns, and then the blocked thread can obtain the lock and re-enter the executable
State. This mechanism ensures that at the same time for each class instance, at most one of its member functions declared as synchronized is in an executable state (because at most only
A lock that can obtain the corresponding instance of the class, thus effectively avoiding access violations of class member variables (as long as all methods that may access the class member variable are declared as synchronized)
。
In Java, not only class instances, each class also corresponds to a lock, so we can also declare the static member function of the class as synchronized to control its static
Access to the operator variable.
The Synchronized method is actually equivalent to wrapping all the statements in the method with a synchronized block, and then passing in the This keyword in parentheses in the synchronized block. Of course, if it is a static method, it is a class object that needs to be locked.
It is possible that only a few lines of code in a method involve thread synchronization, so the synchronized block is more granular than the Synchronized method to control access to multiple threads, and only the contents of the synchronized block cannot be accessed by multiple threads at the same time. The other statements in the method can still be accessed by multiple threads at the same time (both before and after the synchronized block).
explanation of running results
With the understanding of the principle of synchronized, and then see the above procedure can be solved.
1, synchronous common method results:
Although Method1 and Method2 are different methods, both of these methods are synchronized and are called by the same object, so the call must first compete with the lock on the same object (monitor), and it can only get the lock mutually exclusive, so Method1 and METHOD2 can only be executed sequentially.
2, synchronous static method results:
Although Test and test2 belong to different objects, test and test2 belong to different instances of the same class, because both Method1 and method2 are static synchronous methods, so calls need to get the same class monitor (only one class object for each) , so it can only be executed sequentially.
3, code block synchronization results:
For code block synchronization, you essentially need to get the monitor of the object in parentheses after the Synchronized keyword, because the contents of the parentheses in this code are this, and method1 and METHOD2 are called by the same object. So you need to compete for locks on the same object before entering the synchronization block, so you can only execute the synchronization blocks sequentially.
Java synchronized and its implementation principle