【发布时间】:2018-09-03 17:17:22
【问题描述】:
我试图重现 Java 多线程中的非易失性变量行为。
在这里,我在 OccurrenceCounter.java 类中有非易失性变量 test。
在 ThreadDemo.java 类中,我有 main 产生两个线程的方法。
在thread1 中它不断检查非易失变量test 的值
在while循环中。
如果我在 MyRunnableThread1.java 中运行下面的示例,occurrenceCounter.isTest() 的值不会从 CPU 缓存中获取。
OccurrenceCounter.java:
public class OccurrenceCounter {
// non-volatile variable
private boolean test=true;
public OccurrenceCounter(boolean test)
{
this.test=test;
}
public boolean isTest() {
return test;
}
public void setTest(boolean test) {
this.test = test;
}
}
MyRunnableThread1.java:
// Thread 1
public class MyRunnableThread1 implements Runnable {
private String threadName;
private OccurrenceCounter occurrenceCounter;
public MyRunnableThread1(String threadName,OccurrenceCounter occurrenceCounter)
{
this.threadName=threadName;
this.occurrenceCounter=occurrenceCounter;
}
@Override
public void run() {
System.out.println("Thread "+threadName + " started");
System.out.println("value of flag:"+occurrenceCounter.isTest());
int i=0;
// random processing code
while(i<1000000000L)
{
i++;
i++;
i++;
}
// checking whether non-volatile variable is taken from cpu cache
while(occurrenceCounter.isTest())
{
}
System.out.println("Thread "+threadName + " finished");
}
}
MyRunnableThread2.java:
// Thread 2
public class MyRunnableThread2 implements Runnable {
private String threadName;
private OccurrenceCounter occurrenceCounter;
public MyRunnableThread2(String threadName,OccurrenceCounter occurrenceCounter)
{
this.threadName=threadName;
this.occurrenceCounter=occurrenceCounter;
}
@Override
public void run() {
System.out.println("Thread "+threadName + " started");
occurrenceCounter.setTest(false);
System.out.println("Thread "+threadName + " finished");
}
}
ThreadDemo.java:
public class ThreadDemo {
public static void main(final String[] arguments) throws InterruptedException {
System.out.println("main thread started");
OccurrenceCounter occurrenceCounter =new OccurrenceCounter(true);
MyRunnableThread1 myRunnableThread1=new MyRunnableThread1("Thread1", occurrenceCounter);
MyRunnableThread2 myRunnableThread2=new MyRunnableThread2("Thread2", occurrenceCounter);
Thread t1=new Thread(myRunnableThread1);
Thread t2=new Thread(myRunnableThread2);
t1.start();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
System.out.println("main thread sleep exception:"+e);
}
t2.start();
System.out.println("main thread finished");
}
}
在 MyRunnableThread1.java 的 while 循环中,即使 OcuurenceCounter 类中的 test 变量是非易失性的,CPU 缓存也不会返回条件 occurrenceCounter.isTest()。
但是如果我删除第一个 while 循环:
while(i<1000000000L)
{
i++;
i++;
i++;
}
然后我可以看到条件occurrenceCounter.isTest() 始终为假,即使它由thread2 更新并且thread1 永远不会终止。
那么为什么会出现这个while循环:
while(i<1000000000L)
{
i++;
i++;
i++;
}
影响非易失性变量的行为?
这是第一个while循环强制从内存而不是thread1的CPU缓存中读取值吗?我试图得到这个答案很多。但我做不到。
请任何人帮助我解决这个问题。
【问题讨论】:
-
如果没有像
volatile、synchronized或 java.util.concurrent 类这样的线程安全机制,线程之间的数据的可见性就无法很好地定义。它可能可见也可能不可见。不要依赖你所观察到的;依靠保证。
标签: java multithreading volatile non-volatile