閱讀841 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Java並發中正確使用volatile

前幾天並發編程群裏有同學對volatile的用法提出了疑問,剛好我記得Twitter有關實時搜索的這個PPT對這個問題解釋的很清晰並有一個實際的應用場景,於是周末把這個問題摘錄了一些和並發相關的內容如下:

並發 – 定義

悲觀鎖 – Pressimistic locking

  1. 一個線性在執行一個操作時持有對一個資源的獨占鎖。(互斥)
  2. 一般用在衝突比較可能發生的場景下

樂觀鎖 – Optimistic locking

  1. 嚐試采用原子操作,而不需要持有鎖;衝突可被檢測,如果發生衝突,具有相應的重試邏輯
  2. 通常用在衝突較少發生的場景下

非阻塞算法 – Non-blocking algorithm

  1. 算法確保對線程間競爭共享資源時候,不會因為互斥而使任一線程的執行無限延遲;

無鎖算法 – Lock-free algorithm

  1. 如果係統整個流程的執行是無阻塞的(係統某一部分可能被短暫阻塞),這種非阻塞算法就是無鎖的。
  2. 無鎖算法比傳統的基於鎖的算法對係統的開銷更小,且更容易在多核多CPU處理器上擴展;
  3. 在實時係統中可以避免鎖帶來的延遲;
  4. CAS (compare and swap)或LL/SC(load linked/store conditional),以及內存屏障相關的指令經常被用在算法實現中。

無等待算法 – Wait-free algorithm

  1. 如果每個線程的執行都是無阻塞的,這種非阻塞算法就是無等待的(比無鎖算法更好)

Java的並發

  1. Java的內存模型並不保證一個線程可以一直以程序執行的順序看到另一個線程對變量的修改,除非兩個線程都跨越了同一個內存屏障。(Safe publication)

Java內存模型

代碼順序規則

  1. 一個線程內的每個動作 happens-before 同一個線程內在代碼順序上在其後的所有動作

volatile變量規則

  1. 對一個volatile變量的讀,總是能看到(任意線程)對這個volatile變量最後的寫入

傳遞性

  1. 如果A happens-before B, B happens-before C,那 A happens-before C

Safe publication案例

class VolatileExample {
	int x = 0;
	volatile int b = 0;

	private void write() {
		x = 5;
		b = 1;
	}

	private void read() {
		int dummy = b;
		while (x != 5) {
		}
	}

	public static void main(String[] args) throws Exception {
		final VolatileExample example = new VolatileExample();
		Thread thread1 = new Thread(new Runnable() {
			public void run() {
				example.write();
			}
		});
		Thread thread2 = new Thread(new Runnable() {
			public void run() {
				example.read();
			}
		});
		thread1.start();
		thread2.start();
		thread1.join();
		thread2.join();
	}
}

x並不需要定義為volatile, 程序裏可以有需要類似x的變量,我們隻需要一個volatile變量b來確保線程a能看到線程1對x的修改:

  1. 根據代碼順序規則,線程1的x=5; happens-before b=1;; 線程2的int dummy = b; happens-before while(x!=5);
  2. 根據volatile變量規則,線程2的b=1; happens-before int dummy=b;
  3. 根據傳遞性,x=5; happens-before while(x!=5);

JSR-133

在JSR-133之前的舊Java內存模型中,雖然不允許volatile變量之間重排序,但舊的Java內存模型仍然會允許volatile變量 與普通變量之間重排序。JSR-133則增強了volatile的內存語義:嚴格限製編譯器(在編譯器)和處理器(在運行期)對volatile變量與普 通變量的重排序,確保volatile的寫-讀和監視器的釋放-獲取一樣,具有相同的內存語義。

延伸閱讀: JSR-133: JavaTM Memory Model and Thread Specification, The JSR-133 Cookbook for Compiler Writers

參考鏈接

  1. https://2011.lucene-eurocon.org/attachments/0002/8787/Busch_twitter_realtime_search_eurocon_11.pdf
  2. https://www.rossbencina.com/code/lockfree
  3. https://rethinkdb.com/blog/lock-free-vs-wait-free-concurrency/
  4. https://www.infoq.com/cn/articles/java-memory-model-4
  5. JSR-133: JavaTM Memory Model and Thread Specification
  6. The JSR-133 Cookbook for Compiler Writers

文章轉自 並發編程網-ifeve.com

最後更新:2017-05-22 16:02:47

  上一篇:go  軟件事務內存導論(六)配置Akka事務
  下一篇:go  如何在 Linux 中產生、加密或解密隨機密碼