我有以下代码:
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关键字
答案 0 :(得分:0)
您应该使用保留volatile字段的原子整数。要了解为什么这很重要,请尝试运行下面的代码。这里有3种类型的变量,普通int
,volatile int
和AtomicInteger
。只有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());
}
}