[Hung the interviewer] 90% of Java interviews in the lock problem solution coup (below)

Like and follow, you won’t get lost!   

Preface

Dry goods sharing-the lock problem in Java The follow-up solution is updated! I wonder if you have thought of it before? Come take a look

Analysis result 3:

Line 1-9 is the object header information before the hashcode. You can see that the 56bit of 1-7B has no value. After printing the hashcode, lines 16-21 have a value. Why is it 1-7B? , Isn't it 0-6B? Because it is little-endian storage. Among them, 12 lines are the result of printing by the hashcode method, and 13 lines are the hashcode I calculated based on the information of 1-7B, so it can be determined that the last seven bytes in the mark work in the java object header store the hashcode information. Then the eight bits in the first byte are stored respectively with age, bias lock information, and object state. The information represented by this 8bit is as shown in the figure below (in fact, there is information in the figure above). This figure will change with the state of the object. However, the following figure shows that the
Insert picture description here
object state in the unlocked state is divided into five states, namely, unlocked, biased lock, lightweight lock, weight lock, and GC mark. Then how can 2bit represent the five states (2bit at most It can only represent 4 states respectively: 00, 01, 10, 11). JVM does a better job by expressing the biased lock and the unlocked state as the same state, and then according to the identification of the biased lock in the figure, it is Lock-free or bias-locked state. What does that mean? Write a code analysis, before writing the code, we first remember the information 00000001 in the unlocked state , and then write an example of biased lock to see the result

Java code and output results:

1 package com.luban.layout; 
2 import org.openjdk.jol.info.ClassLayout; 
3 import static java.lang.System.out; 
4
5 public class JOLExample2 {
6 static A a; 
7 public static void main(String[] args) throws Exception { 
8 //Thread.sleep(5000); 
9 a = new A(); 
10 out.println("befre lock"); 
11 out.println(ClassLayout.parseInstance(a).toPrintable()); 
12 sync(); 
13 out.println("after lock"); 
14 out.println(ClassLayout.parseInstance(a).toPrintable()); 
15 } 
16
17 public static void sync() throws InterruptedException { 
18 synchronized (a){ 
19 System.out.println("我也不知道要打印什么"); 
20 } 
21
22 } 
23 }

 

1 befre lock 
2 com.luban.layout.A object internals: 
3 OFFSET SIZE TYPE DESCRIPTION VALUE 
4 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 
5 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
6 8 4 (object header) 43 c1 00 20 (01000011 11000001 00000000 00100000) (5 36920387) 
7 12 1 boolean A.flag false 
8 13 3 (loss due to the next object alignment) 
9 Instance size: 16 bytes 
10 Space losses: 0 bytes internal + 3 bytes external = 3 bytes total 
11
12 我也不知道要打印什么 
13 after lock 
14 com.luban.layout.A object internals: 
15 OFFSET SIZE TYPE DESCRIPTION VALUE 
16 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 
17 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
18 8 4 (object header) 43 c1 00 20 (01000011 11000001 00000000 00100000) (536920387) 
19 12 1 boolean A.flag false 
20 13 3 (loss due to the next object alignment)

 

Analysis result 4

The above program has only one thread to call the sync method, so it should be biased to lock, but you will find that the output result (the first byte) is still exactly the same as when there is no lock. In fact, this is because the virtual machine is in There is a delay for the biased lock at startup. For example, if you comment out the sleep in the above code, the result will be different, and the result will become 00000101. Of course, for the convenience of testing, we can directly disable the delay through the JVM parameters -XX:+UseBiasedLocking- XX: BiasedLockingStartupDelay=0, think about why the bias lock will be delayed? (Except for this 8bit, other bits store thread information and epochs, no screenshots are taken here), after lock that needs attention, the bias information is still maintained after exiting the synchronization
Insert picture description here

Performance comparison favors locks and lightweight locks:

1 package com.luban.layout; 
2 public class A { 
3 int i; 
4 public synchronized void parse(){ 
5 i++; 
6 } 
7 }

 

1 package com.luban.layout; 
2 import org.openjdk.jol.info.ClassLayout;
3 import static java.lang.System.out; 
4 //‐XX:BiasedLockingStartupDelay=20000 ‐XX:BiasedLockingStartupDelay=0 
5 public class JOLExample3 { 
6 public static void main(String[] args) throws Exception { 
7 A a = new A(); 
8 long start = System.currentTimeMillis(); 
9 //调用同步方法1000000000L 来计算1000000000L的++,对比偏向锁和轻量级锁的性能 
10 //如果不出意外,结果灰常明显 
11 for(int i=0;i<1000000000L;i++){ 
12 a.parse(); 
13 } 
14 long end = System.currentTimeMillis(); 
15 System.out.println(String.format("%sms", end ‐ start)); 
16
17 } 
18
19 }

 

So the question is, what is a lightweight lock? How does it work? Why is it slower than bias lock? Lightweight locks try to solve the thread synchronization problem at the application level without triggering the mutual exclusion operation of the operating system. Lightweight locks reduce the chance of multiple threads entering mutual exclusion, and cannot replace mutual exclusion.

First look at the object header of the lightweight lock

1 package com.luban.layout; 
2 import org.openjdk.jol.info.ClassLayout; 
3 import static java.lang.System.out; 
4
5 public class JOLExample5 { 
6 static A a; 
7 public static void main(String[] args) throws Exception { 
8 a = new A(); 
9 out.println("befre lock"); 
10 out.println(ClassLayout.parseInstance(a).toPrintable()); 
11 sync(); 
12 out.println("after lock"); 
13 out.println(ClassLayout.parseInstance(a).toPrintable()); 
14 } 
15
16 public static void sync() throws InterruptedException {
17 synchronized (a){ 
18 out.println("lock ing"); 
19 out.println(ClassLayout.parseInstance(a).toPrintable()); 
20 } 
21 } 
22 }

 

Performance comparison, light weight and weight:

1 package com.luban.layout; 
2
3 import java.util.concurrent.CountDownLatch; 
4
5 public class JOLExample4 { 
6 static CountDownLatch countDownLatch = new CountDownLatch(1000000000); 
7 public static void main(String[] args) throws Exception { 
8 final A a = new A(); 
9
10 long start = System.currentTimeMillis(); 
11
12 //调用同步方法1000000000L 来计算1000000000L的++,对比偏向锁和轻量级锁的性能 
13 //如果不出意外,结果灰常明显 
14 for(int i=0;i<2;i++){ 
15 new Thread(){ 
16 @Override 
17 public void run() { 
18 while (countDownLatch.getCount() > 0) {
19 a.parse(); 
20 } 
21 } 
22 }.start(); 
23 } 
24 countDownLatch.await(); 
25 long end = System.currentTimeMillis(); 
26 System.out.println(String.format("%sms", end ‐ start));
27
28 } 
29
30 }

 

Insert picture description here

Regarding the weight lock, first look at the object head

1 package com.luban.layout; 
2 import org.openjdk.jol.info.ClassLayout; 
3 import static java.lang.System.out; 
4
5 public class JOLExample6 { 
6 static A a; 
7 public static void main(String[] args) throws Exception {
8 //Thread.sleep(5000); 
9 a = new A(); 
10 out.println("befre lock"); 
11 out.println(ClassLayout.parseInstance(a).toPrintable()); 
12
13 Thread t1= new Thread(){ 
14 public void run() { 
15 synchronized (a){ 
16 try { 
17 Thread.sleep(5000); 
18 System.out.println("t1 release"); 
19 } catch (InterruptedException e) { 
20 e.printStackTrace(); 
21 } 
22 } 
23 } 
24 }; 
25 t1.start(); 
26 Thread.sleep(1000); 
27 out.println("t1 lock ing"); 
28 out.println(ClassLayout.parseInstance(a).toPrintable()); 
29 sync(); 
30 out.println("after lock"); 
31 out.println(ClassLayout.parseInstance(a).toPrintable()); 
32
33 System.gc(); 
34 out.println("after gc()"); 
35 out.println(ClassLayout.parseInstance(a).toPrintable()); 
36 } 
37
38 public static void sync() throws InterruptedException { 
39 synchronized (a){ 
40 System.out.println("t1 main lock"); 
41 out.println(ClassLayout.parseInstance(a).toPrintable()); 
42 } 
43 } 
44 }

 

If the wait method is called, it immediately becomes a weight lock

1 package com.luban.layout; 
2
3 import org.openjdk.jol.info.ClassLayout; 
4
5 import static java.lang.System.out; 
6
7 public class JOLExample7 { 
8 static A a; 
9 public static void main(String[] args) throws Exception { 
10 //Thread.sleep(5000); 
11 a = new A(); 
12 out.println("befre lock"); 
13 out.println(ClassLayout.parseInstance(a).toPrintable()); 
14
15 Thread t1= new Thread(){ 
16 public void run() { 
17 synchronized (a){ 
18 try { 
19 synchronized (a) { 
20 System.out.println("before wait");
21 out.println(ClassLayout.parseInstance(a).toPrintable()); 
22 a.wait(); 
23 System.out.println(" after wait"); 
24 out.println(ClassLayout.parseInstance(a).toPrintable()); 
25 }
26 } catch (InterruptedException e) {
27 e.printStackTrace(); 
28 } 
29 } 
30 } 
31 }; 
32 t1.start(); 
33 Thread.sleep(5000); 
34 synchronized (a) { 
35 a.notifyAll(); 
36 } 
37 } 
38 }

 

It should be noted that if the object has already calculated the hashcode, it cannot be biased.

1 package com.luban.layout; 
2 import org.openjdk.jol.info.ClassLayout; 
3 import static java.lang.System.out; 
4
5 public class JOLExample8 { 
6 static A a; 
7 public static void main(String[] args) throws Exception { 
8
9 Thread.sleep(5000); 
10 a = new A(); 
11 a.hashCode(); 
12 out.println("befre lock"); 
13 out.println(ClassLayout.parseInstance(a).toPrintable()); 
14
15 Thread t1= new Thread(){ 
16 public void run() { 
17 synchronized (a){ 
18 try { 
19 synchronized (a) {
20 System.out.println("lock ed"); 
21 out.println(ClassLayout.parseInstance(a).toPrintable()); 
22 }
23 } catch (Exception e) { 
24 e.printStackTrace(); 
25 } 
26 }
27 } 
28 }; 
29 t1.start();
30
31 } 
32 }

Guess you like

Origin blog.csdn.net/weixin_50333534/article/details/109321671