文章轉Hollis博客 大家可以關注下,很多技術類型的文章
在再有人問你Java內存模型是什么,就把這篇文章發給他。中我們曾經介紹過,Java語言為了解決並發編程中存在的原子性、可見性和有序性問題,提供了一系列和並發處理相關的關鍵字,比如synchronized
、volatile
、final
、concurren包
等。
在《深入理解Java虛擬機》中,有這樣一段話:
synchronized
關鍵字在需要原子性、可見性和有序性這三種特性的時候都可以作為其中一種解決方案,看起來是“萬能”的。的確,大部分並發控制操作都能使用synchronized來完成。
海明威在他的《午后之死》說過的:“冰山運動之雄偉壯觀,是因為他只有八分之一在水面上。”對於程序員來說,synchronized
只是個關鍵字而已,用起來很簡單。之所以我們可以在處理多線程問題時可以不用考慮太多,就是因為這個關鍵字幫我們屏蔽了很多細節。
那么,本文就圍繞synchronized
展開,主要介紹synchronized
的用法、synchronized
的原理,以及synchronized
是如何提供原子性、可見性和有序性保障的等。
synchronized的用法
synchronized
是Java提供的一個並發控制的關鍵字。主要有兩種用法,分別是同步方法和同步代碼塊。也就是說,synchronized
既可以修飾方法也可以修飾代碼塊。
/** * @author Hollis 18/08/04. */ public class SynchronizedDemo { //同步方法 public synchronized void doSth(){ System.out.println("Hello World"); } //同步代碼塊 public void doSth1(){ synchronized (SynchronizedDemo.class){ System.out.println("Hello World"); } } }
被synchronized
修飾的代碼塊及方法,在同一時間,只能被單個線程訪問。
synchronized的實現原理
synchronized
,是Java中用於解決並發情況下數據同步訪問的一個很重要的關鍵字。當我們想要保證一個共享資源在同一時間只會被一個線程訪問到時,我們可以在代碼中使用synchronized
關鍵字對類或者對象加鎖。
在深入理解多線程(一)——Synchronized的實現原理中我曾經介紹過其實現原理,為了保證知識的完整性,這里再簡單介紹一下,詳細的內容請去原文閱讀。
我們對上面的代碼進行反編譯,可以得到如下代碼:
public synchronized void doSth(); descriptor: ()V flags: ACC_PUBLIC, ACC_SYNCHRONIZED Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello World 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return public void doSth1(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=1 0: ldc #5 // class com/hollis/SynchronizedTest 2: dup 3: astore_1 4: monitorenter 5: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 8: ldc #3 // String Hello World 10: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 13: aload_1 14: monitorexit 15: goto 23 18: astore_2 19: