Can false sharing occur with the following state:
Class Foo{
int x;
int y;
}
Whlie two threads are modifying concurrently x and y? Or is it not possible to judge as compiler might optimize x and y to registers?
Can false sharing occur with the following state:
Class Foo{
int x;
int y;
}
Whlie two threads are modifying concurrently x and y? Or is it not possible to judge as compiler might optimize x and y to registers?
Of course it could happen (could being the keyword here), you can't tell for sure if these two variables will end-up on the same cache-line obviously. Compilers will not do anything (at least javac
) to prevent such scenarios as making these variables to be held on different cache lines would be probably very expensive and it would require a lot of proof that is actually needed.
And yes also, your comment is correct, cache invalidation would happen quite often and might be a cause of a bottleneck. But measuring this is not easy, you can see an example here.
Just notice that since jdk-8 there is @Contended
that would pad entries to fit on exactly a cache line.
test case like this:
public class FalseSharing implements Runnable {
public final static int NUM_THREADS = 2; // change
public final static long ITERATIONS = 50L * 1000L * 1000L;
private static VolatileLong[] longs = new VolatileLong[NUM_THREADS];
static {
for (int i = 0; i < longs.length; i++) {
longs[i] = new VolatileLong();
}
}
private final int arrayIndex;
public FalseSharing(final int arrayIndex) {
this.arrayIndex = arrayIndex;
}
public static void main(final String[] args) throws Exception {
final long start = System.currentTimeMillis();
runTest();
System.out.println("duration = " + (System.currentTimeMillis() - start));
}
private static void runTest() throws InterruptedException {
Thread[] threads = new Thread[NUM_THREADS];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new FalseSharing(i));
}
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
t.join();
}
}
public void run() {
long i = ITERATIONS + 1;
while (0 != --i) {
longs[arrayIndex].value = i;
}
}
public final static class VolatileLong {
public long p1, p2, p3, p4, p5, p6, p7; // padding
public long value = 0L; // change to volatile when test
public long p1_1, p2_1, p3_1, p4_1, p5_1, p6_1, p7_1; // padding
}}
test result(5 times)(run in Intel Core i5 with 2 core):
so in my opinion, false sharing will not occur with non-volatile field
My test prove same thing as yours.
I'm also using com.lmax.disruptor.Sequence to test.
non-volatile long > volatile long use lasyset(Sequence.set) > Sequence.setVolatile == volatile long with padding > volatile long without padding