在Java中挑格,偽共享(false sharing)是指多線(xiàn)程環(huán)境下焚虱,由于緩存一致性協(xié)議的影響基矮,不同線(xiàn)程訪(fǎng)問(wèn)同一緩存行中的不同數(shù)據(jù)造成的性能下降現(xiàn)象会放。當(dāng)多個(gè)線(xiàn)程同時(shí)訪(fǎng)問(wèn)不同變量,但這些變量存儲(chǔ)在同一緩存行中時(shí)诫隅,每個(gè)線(xiàn)程只修改自己的變量腐魂,但由于緩存一致性協(xié)議的要求帐偎,需要將整個(gè)緩存行的數(shù)據(jù)進(jìn)行更新逐纬,導(dǎo)致其他線(xiàn)程緩存的數(shù)據(jù)失效,從而影響了性能削樊。
接下里筆者用一段簡(jiǎn)單的Java代碼豁生,來(lái)演示下偽共享的效果:
public class FalseSharingDemo implements Runnable {
private static final int NUM_THREADS = 2;
private static final long ITERATIONS = 500000000L;
private static final int ARRAY_SIZE = 8;
private static VolatileLong[] longs = new VolatileLong[ARRAY_SIZE];
static {
for (int i = 0; i < ARRAY_SIZE; i++) {
longs[i] = new VolatileLong();
}
}
private final int arrayIndex;
public FalseSharingDemo(int arrayIndex) {
this.arrayIndex = arrayIndex;
}
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; i++) {
threads[i] = new Thread(new FalseSharingDemo(i));
}
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
t.join();
}
}
public void run() {
long i = ITERATIONS + 1;
while (--i > 0) {
longs[arrayIndex].value = i;
}
}
public static class VolatileLong {
public volatile long value = 0L;
}
}
在上面的示例代碼中,我們創(chuàng)建了一個(gè)包含多個(gè)VolatileLong對(duì)象的數(shù)組漫贞。每個(gè)VolatileLong對(duì)象都包含一個(gè)volatile修飾的long類(lèi)型的變量甸箱。在run()方法中,每個(gè)線(xiàn)程都會(huì)通過(guò)循環(huán)將自己的索引對(duì)應(yīng)的VolatileLong對(duì)象的value字段設(shè)置為遞減的值迅脐。
當(dāng)我們運(yùn)行該示例代碼時(shí)芍殖,由于VolatileLong對(duì)象存儲(chǔ)在同一緩存行中,不同線(xiàn)程對(duì)不同的VolatileLong對(duì)象進(jìn)行操作谴蔑,但由于緩存一致性協(xié)議的要求豌骏,每次寫(xiě)操作都會(huì)導(dǎo)致整個(gè)緩存行的數(shù)據(jù)失效。這將引起多個(gè)線(xiàn)程之間頻繁的緩存行無(wú)效和更新隐锭,導(dǎo)致性能下降窃躲。
為了解決偽共享問(wèn)題,可以使用填充(padding)技術(shù)來(lái)確保不同變量在不同的緩存行中钦睡,從而避免了不必要的緩存行無(wú)效和更新蒂窒。可以通過(guò)在VolatileLong類(lèi)中增加填充字段來(lái)解決偽共享問(wèn)題,例如:
public static class VolatileLong {
public volatile long value = 0L;
public long padding1, padding2, padding3, padding4, padding5, padding6;
}
通過(guò)在VolatileLong類(lèi)中添加填充字段洒琢,可以將不同的VolatileLong對(duì)象分散到不同的緩存行中秧秉,從而避免了偽共享帶來(lái)的性能下降。