68
技術社區[雲棲]
Java並發——核心理論
並發編程是Java程序員最核心的技能之一,同時也是掌握難度最大的一部分。我們都知道Java中提供了各種異步機製,但無論是notify
wait
、synchronized
、volatile
亦或是java.util.conccurrent
包下的ReentrantLock
、ThreadPoolExecutor
都遵循著相同的異步理論,要理解上述並發機製就必須首先了解Java異步的核心原理。
1 共享性
數據共享性是線程安全的主要原因之一。如果數據隻在某一個線程中被訪問則不存在共享性問題。然而在多線程環境下常常是多個線程共享一部分數據,為保證在多線程環境下共享數據的一致性,必須引入進程間的同步機製。
2 互斥性
資源互斥是指同時隻允許一個訪問者對其進行訪問,具有唯一性和排它性。我們通常允許多個線程同時對數據進行讀操作,但同一時間內隻允許一個線程對數據進行寫操作。所以我們通常將鎖分為共享鎖和排它鎖,也叫做讀鎖和寫鎖。如果資源不具有互斥性,即使是共享資源,我們也不需要擔心線程安全。例如,對於不可變的數據共享,所有線程都隻能對其進行讀操作,所以不用考慮線程安全問題。但是對共享數據的寫操作,一般就需要保證互斥性。Java 中提供多種機製來保證互斥性,最簡單的方式是使用Synchronized。
3 原子性
所謂原子性指的是一係列不可分割的,獨立的操作,換句話說就是如果執行一個原子性操作,要麼不執行,要麼執行完該原子性操作,不會出現隻做一半的情況。最底層的原子性操作是操作係統的指令。但Java層麵的操作往往是由多個原子性操作構成的,要保證Java操作的原子性最常見的方式就是加鎖,如Java中的Synchronized或Lock都可以實現,代碼段二就是通過Synchronized實現的。除此之外還有一種方式是CAS(Compare And Swap):即修改數據之前先比較與之前讀取到的值是否一致,如果一致,則進行修改,如果不一致則重新執行,這也是樂觀鎖的實現原理。
4 可見性
在多線程環境下,每一個線程都維護一個本地的工作內存,線程操作一個共享變量時並不是直接操作在主內存中的變量,而是將其先拷貝到自己工作內存後再就行修改,同時在修改完成後再同步到主內存。而所謂可見性就是當某一個線程改變某一共享變量後,另一線程可以感知到這一變化。Java中通過Synchronized
和volatile
來保證可見性。
5 有序性
學過體係結構的朋友都知道,為了提高程序運行的效率,CPU會對指令進行重排序,以實現指令級並行。其實在現代操作係統中,除了指令級重排序外,編譯器和內存係統也會進行相應的重排序以提升效率。
在單線程環境下,以上的重排序是不會改變程序的運行邏輯的。但是到了多線程環境,這樣的重排序則可能導致邏輯錯亂。Java中通過Synchronized
和volatile
來保證順序性。
最後更新:2017-07-26 09:04:21