Pessimistic lock / optimistic lock:
Pessimistic: do not allow other threads to intervene during operation. synchronized,lock
Optimistic: other threads can intervene. Reference version number mechanism, CAS
1. Eight lock phenomenon - lock static state / lock method
1.0 standard access thread, print Email first and then SMS:
class Phone{ public synchronized void sendEmail(){ System.out.println("-----sendEmail"); } public synchronized void sendSMS(){ System.out.println("-----sendSMS"); } public void hello(){ System.out.println("-------hello"); } } public class Lock8Demo { public static void main(String[] args) { Phone phone = new Phone(); new Thread(()->{ phone.sendEmail(); },"t1").start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->{ phone.sendSMS(); },"t2").start(); } }
It has nothing to do with sleep() in the middle.
1.1: print email or SMS first
class Phone{ public synchronized void sendEmail(){ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-----sendEmail"); } public synchronized void sendSMS(){ System.out.println("-----sendSMS"); } } public class Lock8Demo { public static void main(String[] args) { Phone phone = new Phone(); new Thread(()->{ phone.sendEmail(); },"t1").start(); new Thread(()->{ phone.sendSMS(); },"t2").start(); } }
result:
-----sendEmail -----sendSMS
1.2 add normal hello(), print mail or hello()
class Phone{ public synchronized void sendEmail(){ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-----sendEmail"); } public synchronized void sendSMS(){ System.out.println("-----sendSMS"); } public void hello(){ System.out.println("-------hello"); } } public class Lock8Demo { public static void main(String[] args) { Phone phone = new Phone(); new Thread(()->{ phone.sendEmail(); },"t1").start(); new Thread(()->{ phone.hello(); },"t2").start(); } }
result:
-------hello -----sendEmail The object of the lock is the object. Ordinary lock free methods do not compete. There is no conflict between lock free methods and lock free methods???
1.3 add a phone object, print Email or SMS first?
class Phone{ public synchronized void sendEmail(){ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-----sendEmail"); } public synchronized void sendSMS(){ System.out.println("-----sendSMS"); } public void hello(){ System.out.println("-------hello"); } } public class Lock8Demo { public static void main(String[] args) { Phone phone = new Phone(); Phone phone1 = new Phone(); new Thread(()->{ phone.sendEmail(); },"t1").start(); new Thread(()->{ phone1.sendSMS(); },"t2").start(); } }
result:
-----sendSMS -----sendEmail
1.4 for two static synchronization methods, the same mobile phone, print E or S first?
The common synchronization method locks the instance object of new; Static methods lock classes..
class Phone{ public static synchronized void sendEmail(){ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-----sendEmail"); } public static synchronized void sendSMS(){ System.out.println("-----sendSMS"); } } public class Lock8Demo { public static void main(String[] args) { Phone phone = new Phone(); new Thread(()->{ phone.sendEmail(); },"t1").start(); new Thread(()->{ phone.sendSMS(); },"t2").start(); } }
result:
-----sendEmail -----sendSMS
1.5 two phone objects, two static synchronization methods, print email or SMS first?
-----sendEmail -----sendSMS
1.6: a static synchronization method, a common synchronization method, e-mail or SMS?
class Phone{ public static synchronized void sendEmail(){ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-----sendEmail"); } public synchronized void sendSMS(){ System.out.println("-----sendSMS"); } } public class Lock8Demo { public static void main(String[] args) { Phone phone = new Phone(); new Thread(()->{ phone.sendEmail(); },"t1").start(); new Thread(()->{ phone.sendSMS(); },"t2").start(); } }
result:
-----sendSMS -----sendEmail Conclusion: there are two different locks: class lock and object lock accessed by two threads
1.7: a static synchronization method, a common synchronization method, and two phone objects:
class Phone{ public static synchronized void sendEmail(){ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-----sendEmail"); } public synchronized void sendSMS(){ System.out.println("-----sendSMS"); } } public class Lock8Demo { public static void main(String[] args) { Phone phone = new Phone(); Phone phone1 = new Phone(); new Thread(()->{ phone.sendEmail(); },"t1").start(); new Thread(()->{ phone1.sendSMS(); },"t2").start(); } }
result:
-----sendSMS -----sendEmail
Programming protocol:
In addition, the loss of lock performance shall be considered, and no lock shall be available as far as possible; If the block can be locked, the method body will not be locked; If you can use object locks, you don't need class locks.
★ conclusion:
0-1. If there are multiple synchronized methods in an object, as long as one thread calls one of the synchronized methods at a certain time, other threads can only wait.
The lock is the current object this. After being locked, other objects cannot enter the synchronized method of the current thread.
2-3. After adding the common method, it has nothing to do with the synchronous lock;
After adding an object, there is no competition for resources
4-5. After changing to static methods, the situation changes again: (class lock or object lock?)
- Common synchronization method: the current instance object of the lock, usually tihs, is a specific mobile phone. All common synchronization methods use the same instance object itself
- For static synchronization method: lock the current class object, such as phone Class is the only class template;
- For fast synchronization methods, the lock is the object in synchronized parentheses
6-7: common synchronization method: instance object lock is used
Static synchronization method: class lock is used
Object lock and class lock are two different locks!!! Irrelevant!!!
2.synchronized bytecode
2.1 lock code block normally
public class Lock8ByteCode { Object object= new Object(); public void m1(){ synchronized (object){ System.out.println("-------im synchronized"); } } public static void main(String[] args) { } }
Bytecode:
6: monitorenter 7: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 10: ldc #5 // String -------im synchronized 12: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 15: aload_1 16: monitorexit 17: goto 25 20: astore_2 21: aload_1 22: monitorexit
One moniterenter corresponds to two monitorexit s:
One exit exits the code block normally, and the other guarantees to exit the code block when an exception occurs
Add a runtime exception to the locked code block:
public class Lock8ByteCode { Object object= new Object(); public void m1(){ synchronized (object){ System.out.println("-------im synchronized"); throw new RuntimeException("-----exit"); } } public static void main(String[] args) { } }
Bytecode:
6: monitorenter 7: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 10: ldc #5 // String -------im synchronized 12: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 15: new #7 // class java/lang/RuntimeException 18: dup 19: ldc #8 // String -----exit 21: invokespecial #9 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V 24: athrow 25: astore_2 26: aload_1 27: monitorexit 28: aload_2 29: athrow
You can see that the monitorexit is wrapped by two athrow s, and there is only one monitorexit
2.2 add to the method:
Calling the instruction will check the ACC of the method_ Whether the synchronized access flag is set. If it is set, the execution thread will hold the monitor first, then execute the method, and release it after completion (whether normal completion or abnormal completion).
2.3 synchronized static synchronization method:
One more ACC_STATIC, others are the same as 2.2.
Why can any object become a lock
ObjectMonitor.java→ObjectMonitor.cpp→objectMonitor.hpp
Each object is born with an object monitor.