在java中解释这种情况下的volatile

时间:2014-10-17 06:05:11

标签: java

我有以下代码:

class Example {
    private volatile int testValue = 0;

    public int getTestValue() {
       return testValue;
    }

    public void setTestValue(int testValue) {
       this.testValue = testValue;
    }

    public void increment() {
       this.testValue += 1;
    }
}

class PrintThread extends Thread {
    private Example example;    
    private int x = 0;

    public PrintThread(Example example) {   
       this.example = example;
       x = example.getTestValue();  
    }

    public void run() {
        while(true) {
            if(x != example.getTestValue()) {   // block 1
                System.out.println("printThread: " + example.getTestValue());
                x = example.getTestValue();
            }
        }
    }
}

class IncrementorThread extends Thread {

    private Example example;

    public IncrementorThread(Example example) {
        this.example = example;
    }

    public void run() {

        while(true) {
          example.increment();
          System.out.println("incrementorThread: " + example.getTestValue());

           try {
              Thread.sleep(800);
           } catch(Exception ex) {

           }
        }
    }
}

public class VolatileExample {
    public static void main(String args[]) {
        Example ex = new Example();
        new IncrementorThread(ex).start();
        new PrintThread(ex).start();
    }
}

当我在Example类中删除volatile关键字时,我从未看到PrintThread的输出。在PrintThread中,当我打印出示例的testValue时,示例对象的值仍然更新,但代码在'块1'永远不会被执行两个线程仍然访问同一个对象,任何人都可以向我解释更多关于此的细节吗?关于在这种情况下受影响的volatile关键字

1 个答案:

答案 0 :(得分:0)

您应该使用保留volatile字段的原子整数。要了解为什么这很重要,请尝试运行下面的代码。这里有3种类型的变量,普通intvolatile intAtomicInteger。只有AtomicInteger才能确保线程的安全性。运行这个简单的代码后,您将看到原因。

public class Test {

    private int threadCount = 10;
    private int nonVolatileCount = 0;
    private volatile int volatileCount = 0;
    private AtomicInteger atomicCount = new AtomicInteger(0);
    private CountDownLatch startLatch = new CountDownLatch(threadCount);
    private CountDownLatch endLatch = new CountDownLatch(threadCount);

    private class Task implements Runnable {

        public void run() {
            startLatch.countDown();
            try {
                startLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (int i = 0; i < 1000000; i++) {
                nonVolatileCount++;
                volatileCount++;
                atomicCount.incrementAndGet();
            }
            endLatch.countDown();
        };
    }

    public static void main(String[] args) throws InterruptedException {
        new Test().go();

    }

    public void go() throws InterruptedException {
        for (int i = 0; i < threadCount; i++) {
            new Thread(new Task()).start();
        }
        endLatch.await();
        System.out.println("non volatile counter: " + nonVolatileCount);
        System.out.println("    volatile counter: " + volatileCount);
        System.out.println("      atomic counter: " + atomicCount.get());
    }

}