鎖消除和鎖粗化案例分析
鎖消除
/**
* 描述: 鎖粒度演示
* @author karl
* @create 2020-02-11 14:38
*/
public class MySynchronizedTest07 {
private Object object = new Object();
public void method() {
synchronized (object) {
System.out.println("hello world");
}
}
}
- 上述是一個簡單的同步代碼塊的案例,在並發的情況下多個線程是共享MySynchronizedTest07 的成員變量 object所以才達到了鎖的效果。
- 我們再看下面一個案例代碼:
package com.karl.concurrent.syn;
/**
* 描述: 鎖粒度演示
*
* @author karl
* @create 2020-02-11pw 14:38
*/
public class MySynchronizedTest07 {
public void method() {
Object object = new Object();
synchronized (object) {
System.out.println("hello world");
}
}
}
- 上述代碼我們可知將object變成了局部變量,在方法中,方法的的局部變量時線程獨立的,並發的場景每個線程都有各自的object對象,這個時候的鎖就無意義的。
- 我們在編譯上述代碼的時候其實也發現了monitorenter和monitorexit,在字節碼層面看上去還有有鎖的獲取和釋放。
- 這個時候JIT編譯器可以在動態編譯同步代碼的時候,使用一種叫做逃逸分析的技術(后續學習jvm的時候會涉及到),來通過該技術判斷程序中使用的鎖對象是否只被一個線程所使用。而沒有別的線程進行競爭。當這種情況的下,那么JIT編譯器在編譯(將字節碼編程機器碼)這個同步代碼時就不會生成synchronized關鍵字所標識鎖的申請和釋放的機器碼。從而消除鎖的使用流程。這就是鎖消除的原理和案例。
鎖粗化
/**
* 描述: 鎖粗化
*
* @author karl
* @create 2020-02-11 15:15
*/
public class MySynchronizedTest08 {
private Object object = new Object();
public void method() {
synchronized (object) {
System.out.println("hello");
}
synchronized (object) {
System.out.println("world");
}
synchronized (object) {
System.out.println("!");
}
}
}
- 代碼很簡單,在這里就不用做代碼解釋了
- 我們直接看JIt編譯器如何優化上述代碼的。
- JIT編譯器在執行動態編譯的時候。若發現前后相鄰的synchronized塊使用的是同一個鎖對象,那么它就會把這幾個synchronized塊合並成一個較大的同步快,這樣做的好處在於線程執行這些代碼的時候,就無需頻繁申請和釋放鎖了,從而達到申請與釋放一次就可以執行全部的同步代碼塊,從而提高了性能。
總結
- 由於JIT編譯后的是機器碼,不能實際的去操作相應的優化效果。所以先理解理論即可。