package com.haogrgr.test.main; import sun.misc.Contended; /** * Note, to make @Contended work, you must specify "-XX:-RestrictContended" to enable it in the VM arguments. * Besides, you can use "-XX:FieldPaddingWidth" to control the padding size (default is 128bytes) */ @SuppressWarnings("restriction") public final class FalseSharingTest { public final static int NUM_THREADS = 4; public final static long ITERATIONS = 500L * 1000L * 1000L; private static VolatilePaddingLong[] paddingLongs = new VolatilePaddingLong[NUM_THREADS]; private static VolatileNativeLong[] nativeLongs = new VolatileNativeLong[NUM_THREADS]; private static ContendedLongs contendedLongs = new ContendedLongs(); static { // init for (int i = 0; i < paddingLongs.length; i++) { paddingLongs[i] = new VolatilePaddingLong(); } for (int i = 0; i < nativeLongs.length; i++) { nativeLongs[i] = new VolatileNativeLong(); } } public static void main(final String[] args) throws Exception { System.out.println("========= With Padding =========="); final long start = System.nanoTime(); runPaddingLongTest(); System.out.println(String.format("duration = %,dns", (System.nanoTime() - start))); System.out.println(); System.out.println("========= Without Padding ========"); final long start2 = System.nanoTime(); runNativeLongTest(); System.out.println(String.format("duration = %,dns", (System.nanoTime() - start2))); System.out.println(); System.out.println("========= With Contended Annotation ========"); final long start3 = System.nanoTime(); runContendedLongTest(); System.out.println(String.format("duration = %,dns", (System.nanoTime() - start3))); } private static void runPaddingLongTest() throws InterruptedException { Thread[] threads = new Thread[NUM_THREADS]; for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(new PaddingLongRunner(i)); } for (Thread t : threads) { t.start(); } for (Thread t : threads) { t.join(); } } private static void runNativeLongTest() throws InterruptedException { Thread[] threads = new Thread[NUM_THREADS]; for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(new NativeLongRunner(i)); } for (Thread t : threads) { t.start(); } for (Thread t : threads) { t.join(); } } private static void runContendedLongTest() throws InterruptedException { Thread[] threads = new Thread[NUM_THREADS]; for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(new ContendedLongRunner(i)); } for (Thread t : threads) { t.start(); } for (Thread t : threads) { t.join(); } } public final static class VolatilePaddingLong { public volatile long value = 0L; public long p1, p2, p3, p4, p5, p6; // padding } public final static class VolatileNativeLong { public volatile long value = 0L; } public final static class ContendedLongs { @Contended public volatile long value1; @Contended public volatile long value2; @Contended public volatile long value3; @Contended public volatile long value4; } public final static class PaddingLongRunner implements Runnable { public PaddingLongRunner(int threadIdx) { this.threadIdx = threadIdx; } private final int threadIdx; @Override public void run() { long i = ITERATIONS + 1; while (0 != --i) { paddingLongs[threadIdx].value = i; } } } public final static class NativeLongRunner implements Runnable { public NativeLongRunner(int threadIdx) { this.threadIdx = threadIdx; } private final int threadIdx; @Override public void run() { long i = ITERATIONS + 1; while (0 != --i) { nativeLongs[threadIdx].value = i; } } } public final static class ContendedLongRunner implements Runnable { public ContendedLongRunner(int threadIdx) { this.threadIdx = threadIdx; } private final int threadIdx; @Override public void run() { switch (threadIdx) { case 0: doRunForContendedValue1(); break; case 1: doRunForContendedValue2(); break; case 2: doRunForContendedValue3(); break; case 3: doRunForContendedValue4(); break; default: throw new RuntimeException(); } } public void doRunForContendedValue1() { long i = ITERATIONS + 1; while (0 != --i) { contendedLongs.value1 = i; } } public void doRunForContendedValue2() { long i = ITERATIONS + 1; while (0 != --i) { contendedLongs.value2 = i; } } public void doRunForContendedValue3() { long i = ITERATIONS + 1; while (0 != --i) { contendedLongs.value3 = i; } } public void doRunForContendedValue4() { long i = ITERATIONS + 1; while (0 != --i) { contendedLongs.value4 = i; } } } }