synchronized & volatile
[toc]
實(shí)現(xiàn)多線程的兩種方式:①、繼承 Thread 類;②、實(shí)現(xiàn) Runnable 接口(推薦使用)。
非線程安全:多個線程對同一個對象中的同一個實(shí)例變量進(jìn)行操作時會出現(xiàn)值被更改、值不同步的情況,進(jìn)而影響程序的執(zhí)行流程。
守護(hù)線程:是為其他線程的運(yùn)行提供便利服務(wù)的,最典型的應(yīng)用就是 GC(垃圾回收線程)。
synchronized 關(guān)鍵字
synchronized 取得的鎖都是對象鎖,擁有鎖重入的功能。
鎖重入:當(dāng)一個線程得到一個對象鎖后,再次請求此對象鎖時,可以再次得到該對象的鎖的。
可重入鎖:比如:有一條線程獲得了某個對象的鎖,此時這個對象鎖還沒有被釋放,當(dāng)其想再次獲取這個對象的鎖時,還是可以獲取的。但如果不可鎖重入的話,就會出現(xiàn)死鎖。
synchronized 方法:對當(dāng)前對象進(jìn)行加鎖;
synchronized 代碼塊:對某一個對象進(jìn)行加鎖,默認(rèn)(this);
synchronized 同步代碼塊
- 同步代碼塊比同步方法范圍小。
- 同步代碼塊可以指定對象鎖。
synchronized(非 this 對象 X)
- synchronized(非 this 對象 X) 代碼塊中的程序,與同步方法是異步的,不會與其他鎖 this 同步方法爭搶 this 鎖,所以大大提高運(yùn)行效率。
- 也解決"臟讀"問題。
靜態(tài)同步 synchronized 方法與 synchronized(Class) 代碼塊
- 非靜態(tài)同步 synchronized 方法是給對象加鎖;靜態(tài)同步 synchronized 方法是給 Class 加鎖的,對類的所有實(shí)例對象起作用。
- synchronized(class) 代碼塊與靜態(tài)同步 synchronized 方法作用一樣。
volatile 關(guān)鍵字
主要作用:使變量在多個線程之間可見。
private boolean isRunning = true; 存在于公共堆棧及線程的私有堆棧中。
volatile 的作用:強(qiáng)制從公共堆棧中取得變量的值,而不是從線程私有堆棧中取得
volatile 最致命的缺點(diǎn):不支持原子性。
Q:volatile & synchronized 的區(qū)別?
- volatile 只能修飾變量,而 synchronized 可以修飾方法、代碼塊
- volatile 性能比 synchronized 好,但是使用幾率不大。
- 多線程訪問 volatile 不會發(fā)生阻塞,而 synchronized 會出現(xiàn)阻塞
- volatile 能保證數(shù)據(jù)的可見性,但不能保證原子性,而 synchronized 可以保證原子性、間接保證可見性(將私有內(nèi)存和公共內(nèi)存中的數(shù)據(jù)做同步)
- volatile 解決的是變量在多個線程之間的可見性,而 synchronized 解決的是多個線程之間訪問資源的同步性
volatile 的非原子性
如果修改實(shí)例變量中的數(shù)據(jù),會出現(xiàn)非線程安全的問題。
,比如:i++,也就是 i = i + 1 并不是一個原子操作,也就是非線程安全的。i++ 的操作步驟分解如下:
- 從內(nèi)存中取出 i 值
- 計算 i 的值(此時,如果一個線程修改 i 的值,就出現(xiàn)臟數(shù)據(jù))
- 將 i 的值寫到內(nèi)存中
Q:為什么使用 volatile 會出現(xiàn)非線程安全的問題?
A:變量在內(nèi)存中工作的過程:
- read & load 階段:從主存復(fù)制變量到當(dāng)前線程工作內(nèi)存
- use & assign 階段:執(zhí)行代碼,改變共享變量值
- store & write 階段:用工作內(nèi)存數(shù)據(jù)刷新主存對應(yīng)變量的值
如果在 read & load 階段之后,變量發(fā)生修改,就會出現(xiàn)私有內(nèi)存和公共內(nèi)存中的變量不同步,從而出現(xiàn)非線程安全問題。
volatile 總結(jié): 對于用 volatile 修飾的變量,JVM 虛擬機(jī)只是保證從主內(nèi)存加載到線程工作內(nèi)存的值是最新的。也就是說,volatile 關(guān)鍵字解決的是變量讀時的可見性問題,但無法保證原子性,對于多個線程訪問同一個實(shí)例變量還是需要加鎖同步。
synchronized 代碼塊有 volatile 同步的功能
synchronized 可以使多個線程訪問同一個資源具有同步性,而且它還具有將線程工作內(nèi)存中的私有變量與公共變量同步的功能。
總結(jié):synchronized 不僅可以解決一個線程看到對象處于不一致的狀態(tài),還可以保證進(jìn)入同步方法或者同步代碼塊的每個線程,都看到由一個鎖保護(hù)之前所有的修改效果。