Synchronous synchronized synchronization method synchronized can be used to lock a method or block of code, and when it modifies a method or a block of code, at most one thread at a time executes the code. This means that when two concurrent threads access the synchronized code block at the same time, two threads can only be queued for serial processing, and another thread waits for the previous thread to execute the block before executing the synchronized code block again.
By using synchronized to decorate a method, the method becomes a synchronous method that can only be executed by one thread at a time. However, synchronized lock mechanism is too heavyweight, not only the entire synchronization method code is locked, even the method used by all the class variables are also locked. Therefore, the more code the synchronization method overwrites, the more severe the lock-up operation will have on the efficiency.
Explicit fingerprint (synchronous code block) to reduce the effect of the synchronization method, we can let synchronized only decorate a block of code, instead of decorating the entire method, synchronized the modified code block is called Synchronous code block. Synchronous code block to specify the key object of the code block, this object can be an instance of any related class, it is equivalent to a fingerprint, each thread executes the synchronization code block must first verify the fingerprint, the same fingerprint thread into the same queue in sequence, if the fingerprint is different into another execution queue.
The following is a code example of a synchronous method and a synchronous code block:
public class Testcode {public static void main (string[] args) {TestCode1 T1 = new TestCode1 (); TestCode2 t2 = new TestCode2 (); TestCode3 t3 = new TestCode3 (); Thread ta = new Thread (T1, "A"); Thread TB = new Thread (t2, "B"); Thread TC = new Thread (T3, "C"); Ta.start (); Tb.start (); Tc.start ();} private static Testcode test = new Testcode ();p ublic static class TestCode1 implements Runnable {public synchronized void Run () {for (int i = 0; i < 5; i++) {try {thread.sleep ()} catch (Interruptedexception e) {e.printstacktrace ()} System.out.println (Thread.CurrentThread (). GetName () + "synchronized loop" +i);}}} public static class TestCode2 implements Runnable {public void run () {synchronized (test) {//here if this is used to represent a new instance, do not engage with other code blocks Together for (int i = 0; i < 5; i++) {try {thread.sleep)} catch (Interruptedexception e) {e.printstacktrace ();} System.out.println (Thread.CurrentThread (). GetName () + "synchronized loop" +i);}}} public static class TestCode3 implements Runnable {public void run () {Synchronized (test) {//here if you use this to represent a new instance, do not get together with other blocks of code for (int i = 0; i < 5; i++) {try {Thread.Sleep (+)};} catch (Interrupted Exception e) {e.printstacktrace ();} System.out.println (Thread.CurrentThread (). GetName () + "synchronized loop" +i);}}}}
The following is the result of the sample code execution:
b synchronized Loop 0A synchronized loop 0A synchronized Loop 1 B synchronized loop 1 B synchronized loop 2A synchronized Lo Op 2B synchronized loop 3 A synchronized loop 3 a synchronized loop 4 B synchronized loop 4C synchronized Loop 0C Synchronize D Loop 1C synchronized loop 2C synchronized loop 3C synchronized Loop 4
As can be seen from the output, the synchronization code block if the lock is the same object instance, then the two synchronous code blocks are also considered mutually exclusive, at the same time can only have two blocks of code one of them is executed, so the log shows: Thread B's synchronization code block has been executed before starting to execute thread B synchronization code block, Even if two blocks of code are in different places.
Implicit fingerprint in front of that, synchronized will lock the class variables inside the synchronization code, so that if the two synchronization code uses a class variable, it will also produce a queued wait situation. Because a thread executes the first synchronization code, the class variable is locked, and then another thread executes the second synchronization code, and is ready to lock the class variable, and the result is that the class variable is locked and cannot be locked again, so the later threads have to wait for the previous thread to finish. In this case, the two synchronization code uses the same class variable, which we can use as an implicit fingerprint, whereas the synchronous code block specifies the key object beforehand, which can be called an explicit thumbprint.
The following is an example code for an implicit fingerprint:
public class Testsynchronized {private int count = 0;public synchronized void Plus () {System.out.println ("Begin plus count = "+count"); count++;try {Thread.Sleep (2000); System.out.println ("End plus count=" +count);} catch (Exception e) {e.printstacktrace ();}} public synchronized void minus () {System.out.println ("Begin minus count=" +count); count--; System.out.println ("End minus count=" +count); public void print () {try {thread.sleep (1000); System.out.println ("Print count=" +count); catch (Exception e) {e.printstacktrace ();}} public static void Main (string[] args) throws Exception {final testsynchronized ts = new testsynchronized (); Thread thread_plus = new Thread ("Thread_plus") {public void run () {System.out.println ("thread:" + super.getname ()); Ts.plus ();}}; Final thread Thread_minus = new Thread ("Thread_minus") {public void run () {System.out.println ("Thread:" + super.getname () );//change the order of execution of Ts.sub and ts.print to see what the situation is Ts.minus (); Ts.print ();//Ts.minus ();}}; Thread_plus.start (); Thread.Sleep (Thread_minus);. Start ();}}
The following is the result of the sample code execution:
Thread:thread_plusbegin plus count=0thread:thread_minusend plus count=1begin minus count=1end minus Count=0print count= 0
As can be seen from the output, the minus thread always begins execution after the plus thread finishes, although the two-thread synchronization method does not specify a locked object, but the two methods use the class variable count internally, so these two methods become exclusive methods that have the same implicit fingerprint.
Locking lock because synchronized is a heavyweight lock that has a large impact on program efficiency and is prone to deviate from expectations, Java introduces the lock interface for lightweight locking operations starting with jdk1.5. The lock interface consists of two derived classes, the normal re-entry lock Reentrantlock, and the read-write lock Reentrantreadwritelock.
The re-entry lock Reentrantlockreentrantlock is a generic lock that is not distinguished by type, and the code between lock and Unlock is a block of code that is locked.
The common methods of Reentrantlock are as follows:
Lock: Add lock. This operation does not allow interrupts, and it waits while repeating locking.
Unlock: Unlock.
Lockinterruptibly: Locking to allow interrupts. Allows the Thread.Interrupt method of a waiting thread to be called by another thread while waiting to interrupt the wait thread's wait and return directly without acquiring the lock and throwing a interruptedexception
Trylock: Try to lock. If the lock is not previously locked, it returns true if it has previously been lock by the current thread, and returns False if it has previously been blocked by another thread.
Getholdcount: Gets the number of locks for the current thread.
IsLocked: Determine if lock is added.
Getqueuelength: Gets the length of the wait queue.
The read-write lock Reentrantreadwritelockreentrantreadwritelock is a mixed lock that distinguishes between read and write locks, which is a shared lock, and a write lock is an exclusive lock.
The common methods of Reentrantreadwritelock are as follows:
Readlock: Get read lock Object Reentrantreadwritelock.readlock
Writelock: Get write Lock Object Reentrantreadwritelock.writelock
Iswritelocked: Determine if a write lock is added.
Getreadholdcount: Gets the number of read locks.
Getwriteholdcount: Gets the number of write locks to be added.
Getqueuelength: Gets the length of the wait queue.
The following are common methods of Reentrantreadwritelock.readlock:
Lock: Read lock.
Lockinterruptibly: Locking to allow interrupts.
Trylock: Try to read the lock.
Unlock: Unlocks the read lock.
The following are common methods of Reentrantreadwritelock.writelock:
Lock: Add write lock.
Lockinterruptibly: Locking to allow interrupts.
Trylock: Try to write the lock.
Unlock: Unlocks the write lock.
Anonymous inner class lock anonymous inner class use synchronized to be careful, although it seems that there is only one synchronization code, but the anonymous inner class each use is to create a new class and instantiate, so the use of anonymous inner class is actually called different classes, not the same kind of internal synchronization method, nature is non-impact. This is a place where anonymous internal classes are often confusing, and it is recommended to use lock plus lock instead of synchronized. For an explanation of the anonymous inner class, see the Android Development Note (86) for a few special classes.
The following is an example code that uses two types of locking methods:
Import Java.text.simpledateformat;import Java.util.date;import Java.util.concurrent.locks.reentrantlock;public Class Testanonymous {public static String Getnowdatetime () {SimpleDateFormat S_format = new SimpleDateFormat ("Yyyy-mm-dd HH:mm:ss ");D ate d_date = new Date (); String s_date = ""; s_date = S_format.format (d_date); return s_date;} private static void Runsync () {for (int i = 0; i < 5; i++) {final int pos = i; Thread t = new Thread () {@Overridepublic synchronized void run () {try {thread.sleep ()} catch (Interruptedexception e) {E.printstacktrace ();} System.out.println (Getnowdatetime () + "Runsync pos=" + pos);}}; T.start ();}} Private final static Reentrantlock lock = new Reentrantlock ();p rivate static void Runlock () {for (int i = 0; i < 5; i++ ) {Final int pos = i; Thread t = new Thread () {@Overridepublic void run () {try {lock.lock (); Thread.Sleep (1000); System.out.println (Getnowdatetime () + "Runlock pos=" + pos);} catch (Interruptedexception e) {e.printstacktrace ();} finally {lock.Unlock ();}}; T.start ();}} public static void Main (string[] args) {runsync (); Runlock ();}}
The following is the result of the sample code execution:
2016-04-20 11:25:36 runsync pos=12016-04-20 11:25:36 runsync pos=42016-04-20 11:25:36 runSync pos=22016-04-20 11:25:36 ru NSync pos=32016-04-20 11:25:36 runsync pos=02016-04-20 11:25:36 runlock pos=02016-04-20 11:25:37 runLock pos=12016-04-20 11:25:38 runlock pos=22016-04-20 11:25:39 runlock pos=32016-04-20 11:25:40 runlock pos=4
As can be seen from the output, in the anonymous inner class, the lock operation of synchronized does not conform to the expected result, and the threads are still executed in random order. In contrast, lock's locking operation is expected and each thread executes sequentially.
Click here to view the full list of Android development notes
Android Development Note (88) Sync and lock