Java多线程中的volatile和伪共享(3)

@Override
    public void run() {
        long i = ITERATIONS + 1;
        while (0 != --i) {
            longs[arrayIndex].value = i;
        }
    }
}

class VolatileLong extends VolatileLongPadding {

public volatile long value = 0L;
}

class VolatileLongPadding {

public volatile long p1, p2, p3, p4, p5, p6, p7;
}

在jdk1.8环境下,缓存行填充终于被JAVA原生支持了。JAVA 8中添加了一个@Contended的注解,添加这个的注解,将会在自动进行缓存行填充。以上的例子可以改为:

package basic;

public class TestFlashONJDK8 implements Runnable {

public static int            NUM_THREADS = 4;
    public final static long      ITERATIONS  = 500L * 1000L * 1000L;
    private final int            arrayIndex;
    private static VolatileLong[] longs;

public TestFlashONJDK8(final int arrayIndex){
        this.arrayIndex = arrayIndex;
    }

public static void main(final String[] args) throws Exception {
        Thread.sleep(10000);
        System.out.println("starting....");
        if (args.length == 1) {
            NUM_THREADS = Integer.parseInt(args[0]);
        }

longs = new VolatileLong[NUM_THREADS];
        for (int i = 0; i < longs.length; i++) {
            longs[i] = new VolatileLong();
        }
        final long start = System.nanoTime();
        runTest();
        System.out.println("duration = " + (System.nanoTime() - 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 TestFlashONJDK8(i));
        }
        for (Thread t : threads) {
            t.start();
        }
        for (Thread t : threads) {
            t.join();
        }
    }

@Override
    public void run() {
        long i = ITERATIONS + 1;
        while (0 != --i) {
            longs[arrayIndex].value = i;
        }
    }
}

@Contended
class VolatileLong {

  public volatile long value = 0L;
}

执行时,必须加上虚拟机参数-XX:-RestrictContended,@Contended注释才会生效。很多文章把这个漏掉了,那样的话实际上就没有起作用。

补充:

byte字节  bit位 1byte=8bit

volatile说明

package basic;

public class TestVolatile {

public static int count = 0;

/* 即使使用volatile,依旧没有达到我们期望的效果 */
    // public volatile static int count = 0;

public static void increase() {
        try {
            // 延迟10毫秒,使得结果明显
            Thread.sleep(10);
            count++;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

public static void main(String[] args) {
        for (int i = 0; i < 10000; i++) {
            new Thread(new Runnable() {

@Override
                public void run() {
                    TestVolatile.increase();
                }
            }).start();
        }
        System.out.println("期望运行结果:10000");
        System.out.println("实际运行结果:" + TestVolatile.count);
    }
}

volatile关键字的使用:用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最新值。但是由于操作不是原子性的,对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的。

Java多线程中的volatile和伪共享

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/9020863d289a098b2e34d0a03afea2fd.html