volatile是輕量級的synchronized。彙編指令中會加入lock字首避免指令重排並把寫緩衝區的所有資料重新整理到記憶體中保證可見性,但不保證原子性。
記憶體屏障:一組處理器指令,實現對記憶體操作的順序限制。
有volatile修飾的變數,在進行寫操作時,會發生兩件事:
lock字首指令會引起處理器快取回寫記憶體,也就是寫乙個volatile變數時,jmm會把執行緒對應的本地記憶體中的共享變數值重新整理到主記憶體。
乙個處理器快取回寫記憶體會導致其他處理器的快取失效。也就是會造成其他執行緒的本地記憶體失效,要從主記憶體讀取共享變數。
volatile的使用優化
佇列集合類linkedtransferqueue,在使用volatile時,用追加位元組的方式優化佇列出隊和入隊效能,將共享變數追加到64位元組。
追加到64個位元組的優點在於,保證了頭結點和尾結點不會被載入到同乙個快取行,頭尾節點在修改時不會被互相鎖定
此優化適用於:快取行為64位元組寬的處理器,並且共享變數會被頻繁的讀寫。
volatile的特性
可見性:對乙個volatile變數的讀,能看到其他執行緒對他的最後寫。
原子性:對單個volatile變數的讀寫具有原子性,但類似 i++,i = i*5不具備原子性。
為了實現volatile的記憶體語義,會在指令序列中插入記憶體屏障,來禁止特定型別的處理器重排序。
寫操作前插入 storestore,保證所有的寫操作已經對任意處理器可見
寫操作後插入storeload,保證不會發生於後續的volatile讀/寫發生重排。
讀操作後插入loadload,保證處理器不會將volatile讀與後續的普通讀重排
讀操作後插入loadstore,保證不會與後續的普通寫重排。
乙個驗證可見性的簡單實驗
先貼**,flag用volatile修飾時,可以正常跳出迴圈,因為寫該變數會把寫執行緒處理過的變數全部寫回主記憶體,而讀該變數時,讀執行緒會將本地記憶體置為無效,去主記憶體中讀取,所以實現了執行緒間的可見性。
package com.xliu.chapter3;
/** * @author liuxin
* @version 1.0
* @date 2020/4/17 17:50
*/public
class
volatileexample
system.out.
println
(a);
system.out.
println
("結束迴圈");
}}public
class
writerthread
extends
thread
}public
static
void
main
(string[
] args)
catch
(interruptedexception e)
volatileexample.
newwriterthread()
.start()
;while
(true)}
}
Linux一點小知識
ps o pid,pgid,ppid,comm cat pid pgid ppid command 17906 17906 17905 bash 18011 18011 17906 ps 18012 18011 17906 cat 1.程序組 pid為程序自身的id,pgid為程序所在的程序組的id...
DNS Client 的一點小知識
因為dns是c s結構,大家又熟悉dns server這個概念,所以很容易產生乙個誤解,認為 dns client服務 就是dns的客戶端。誤以為如果禁用 dns client服務 客戶端就不能解析網域名稱了。產生誤解的原因,還在於微軟的誤導。在windows的服務管理中,微軟聲稱 dns clie...
每天記錄一點小知識
1,2,3 reduce a,b undefined 1 2,3 reduce a,b a b 6 1 2,3 reduce a,b 6function clone obj for var attr in obj return copy msg 分頁函式 param data 分頁渲染的資料 par...