當咱們在進行多線程編程時,若是線程之間不須要共享變量,可是各個線程操做的變量處於同一個cache line時,就會發生「僞共享」現象。這種現象並不會形成程序錯誤,而是若是程序員不注意這個問題會無形下降程序效率。java
cache line又稱做緩存行,是cpu加載數據的一個基本單位,就比如磁盤加載數據的基本單位是一個扇區,windows文件系統加載數據的基本單位是簇。這樣設計的主要目的在於一次性儘可能多加載數據避免重複從內存讀取,進而提升效率。程序員
廢話很少說,先看代碼:編程
public class FalseSharingTest {windows
private static class FalseShareObject {
long p1, p2, p3, p4, p5, p6;
volatile long value;
}緩存
public static void main(String[] args) throws Exception {
FalseShareObject[] fsos = new FalseShareObject[5];
for (int i = 0; i < fsos.length; i++) {
fsos[i] = new FalseShareObject();
}
Thread[] threads = new Thread[fsos.length];
for (int i = 0; i < fsos.length; i++) {
final int idx = i;
threads[idx] = new Thread() {
public void run() {
for (long j = 0; j < 100000000l; j++) {
fsos[idx].value = j;
}
}
};
}多線程
for (Thread t : threads) {
t.start();
}操作系統
long start = System.currentTimeMillis();
for (Thread t : threads) {
t.join();
}
long end = System.currentTimeMillis();
System.out.println("耗時:" + (end - start));
}線程
}
運行耗時:1667毫秒設計
當註釋掉// long p1, p2, p3, p4, p5, p6; 後並無改變程序的語義,運行耗時:5169毫秒指針
運行的結果代表僞共享的現象是確實存在的。
該程序須要注意的是FalseShareObject對象中的value變量用volatile修飾能夠看出明顯的現象,若是去掉後則不明顯。由於根據mesi緩存一致性協議,只有當緩存行的數據與內存數據一致時,處於同一個緩存行的數據才能被其它內核共享,進而使得被共享的緩存行數據在其它內核中產生cache line無效(也就是所謂的cache miss),其他的線程則頻繁的從內存讀取數據到cache line中從而下降效率,從而發生了所謂的「僞共享」現象。
爲何要定義 long p1, p2, p3, p4, p5, p6這幾個變量呢,主要是由於cache line通常大小爲64個字節,而java對象頭在64位操做系統中不開啓指針壓縮佔用16個字節,這樣加上6個long類型的變量後基本能夠確保變量value佔用獨立的緩存行。
代碼下載連接:https://pan.baidu.com/s/16_olDOQqXw612fft6oTGCQ 密碼:i2x3