面試中關於synchronized關鍵字

1、  說說對synchronized關鍵字的瞭解java

    synchronized關鍵字解決的是多個線程之間訪問資源的同步性,synchronized關鍵字能夠保證被它修飾的方法或代碼塊在任意時刻只能有一個線程執行。面試

   另外,在早期的java版本中,synchronized屬於重量級鎖,效率低下,由於監視器鎖(minitor)是依賴於底層的操做系統的Mutex Lock來實現的,java的線程是映射到操做系統的原生線程之上的。若是要掛起或者喚醒一個線程都須要操做系統來幫忙完成,而操做系統實現線程之間的切換時須要從用戶態轉換的內核態,這個狀態之間的轉換須要比較長的時間,因此早期的synchronized效率低下。在java 6以後java官方對從JVM層面對synchronized較大優化。java1.6對鎖的實現引入了大量的優化,如自旋鎖、適應性自旋鎖、鎖消除、鎖粗化、偏向鎖、輕量級鎖等技術來減小鎖操做的開銷。安全

2、synchronized關鍵字的三種使用方式:多線程

      1.修飾實例方法,做用於當前對象實例加鎖,進入同步代碼前要得到當前對象實例的鎖優化

      2.修飾靜態方法,做用於當前類對象加鎖,進入同步代碼前要得到當前類對象的鎖。也就是給當前類加鎖,會做用於當前類的全部對象實例,由於對象靜態成員不屬於任何一個實例對象,是類成員(static代表這是該類的一個靜態資源,無論new了多少對象,只有一份,因此對該類的全部對象都加了鎖)。因此若是一個線程A調用一個實例對象的非靜態synchronized方法,而線程B須要調用這個實例對象所屬類的靜態synchronized方法,是容許的,不會發生互斥現象,由於訪問靜態synchronized方法佔用的鎖是當前類的鎖,而訪問非靜態synchronized方法佔用的鎖是當前實例對象鎖。this

      3.修飾代碼塊,指定加鎖現象,對給定對象加鎖,進入同步代碼塊庫前要得到給定對象的鎖。和synchronized方法同樣,synchronized(this)也是鎖定當前對象的。synchronized關鍵字加到static靜態方法和synchronized(class)代碼塊上都是給Class類上鎖。這裏再提一下:synchronized關鍵字加到非靜態方法上是給對象實例上鎖。另外須要注意的是:儘可能不要使用synchronized(String a)由於在JVM中,字符串常量池具備緩衝功能。spa

        面試中面試官常常會說: 單例模式瞭解嗎?來給我手寫一下!給我解釋一下雙重檢驗鎖方式實現單例模式的原理
              雙重校驗鎖實現對象單例(線程安全)
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
//先判斷對象是否已經實例過,沒有實例化過才進入加鎖代碼if (uniqueInstance == null) {
//類對象加鎖
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
   另外,須要注意uniqueInstance採用volatile關鍵字修飾頗有必要。
    uniqueInstance採用volatile關鍵字修飾頗有必要,uniqueInstance = new SingIeton();這段代碼實際上是分爲三步執行:
    1.爲uniqueInstance分配內存空間
    2.初始化uniqueInstance
    3.將uniqueInstance指向分配的內存地址
  可是因爲JVM具備指令重排的特性,執行順序可能1.3.2。 指令重排在單線程環境下不會出問題,可是在多線程環境下會致使一個線程得到尚未初始化的實例。例如,線程T1執行了1和3,此時T2調用getUniqueInstance()後發現uniqueInstance不爲空,所以返回uniqueInstance,但此時uniqueInstance還未被初始化。使用volatile能夠禁止JVM的重排序,保證多線程環境下也能正常運行
 
3、講一下 synchronized 關鍵字的底層原理
 synchronized 關鍵字底層原理屬於 JVM 層面。
  ① synchronized 同步語句塊的狀況
public class SynchronizedDemo {
public void method() {
synchronized (this) {
System.out.println("synchronized 代碼塊");
}
}
}

synchronized同步語句塊的使用實現的是monitorenter和monitorexit指令,其中monitorenter指令指向同步代碼塊開始位置,monitorexit指令指向同步代碼塊的結束位置。當執行monitorenter指令時,線程試圖獲取鎖也就是獲取monitor(monitor對象存在於每一個java對象的對象頭中,synchronized即是經過這種方式獲取鎖的,也就是java中任意對象能夠做爲鎖的緣由)的持有權,當計數器爲0則成功獲取,獲取後將鎖計數器設爲1也就是加1。相應的在執行monitorenter指令後,將鎖計數器設爲0,代表鎖被釋放。若是獲取對象失敗,那當前對象就要阻塞等待,知道鎖被另外一個線程釋放爲止。操作系統

    synchronized 修飾方法的的狀況線程

public class SynchronizedDemo2 {
public synchronized void method() {
System.out.println("synchronized 方法");
}
}
synchronized 修飾的方法並無 monitorenter 指令和 monitorexit 指令,取得代之的卻 是 ACC_SYNCHRONIZED 標識,該標識指明瞭該方法是一個同步方法, JVM 經過該 ACC_SYNCHRONIZED 訪問標誌來 辨別一個方法是否聲明爲同步方法,從而執行相應的同步調用。
相關文章
相關標籤/搜索