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; } }
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 方法"); } }