这里我有三个简单的类:
第1课:
public class ThreadSyncMain {
public static int count = 0; // volatile is not use
public static void main(String[] args) {
Thread thread1 = new Thread( new Thread1(),"Thread1" );
Thread thread2 = new Thread( new Thread2(),"Thread2");
thread1.start();
thread2.start();
}
}
第2课:
public class Thread1 implements Runnable{
public void run() {
System.out.println("Thread1 Count :: "+ThreadSyncMain.count);
ThreadSyncMain.count++;
}
}
第3课:
public class Thread2 implements Runnable{
public void run() {
System.out.println("Thread2 Count :: "+ThreadSyncMain.count);
}
}
输出结果为:
Thread1 Count :: 0
Thread2 Count :: 1
这意味着thread1更改了count的值。那么为什么更改thread1会影响thread2,因为我没有使用任何“volatile”关键字。在这种情况下,“volatile”关键字不是问题吗?如何修改代码以测试“volatile”?
提前致谢。
更新部分: 在进行一些命中和试验测试之后,我正在更新代码。 1级保持不变。这是更新的代码:
第2类:我加了100毫秒延迟。
public class Thread1 implements Runnable{
public void run() {
System.out.println("Thread1 Count :: "+ThreadSyncMain.count);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadSyncMain.count++;
}
}
第3类:添加while循环。在里面,计数会持续受到监控。
public class Thread2 implements Runnable{
public void run() {
while(true)
{
if(ThreadSyncMain.count == 1)
{
System.out.println("Thread2 Count :: "+ThreadSyncMain.count);
}
}
}
}
现在在这种情况下我得到以下输出:
1.如果class1输出中未使用“volatile”,则为:
Thread1 Count :: 0
2。如果在class1输出中使用“volatile”,则为:
Thread1 Count :: 0
Thread2 Count :: 1
Thread2 Count :: 1
Thread2 Count :: 1
.
.
.
为什么在这种情况下会出现波动?
答案 0 :(得分:3)
每个线程都有一个内存视图。如果不使用锁,则不保证这些视图在线程之间保持一致。因此,如上所述共享变量(没有volatile
)将起作用,因为它在线程中可见,但可能会给您不可靠的结果。使用volatile
关键字意味着变量在线程之间始终读取。
请参阅here,特别注意:
易失性字段是用于通信的特殊字段 线程之间的状态。每次读取volatile都会看到最后一次写入 通过任何线程对那个易变的;实际上,他们是由 程序员作为字段,看到“陈旧”是永远不可接受的 缓存或重新排序的结果。
答案 1 :(得分:3)
Volatile
将保证线程1的副作用对线程2可见。如果没有volatile
,则可能会或可能不会显示更改。
测试volatile
的效果很困难,因为它依赖于低级方面,如硬件架构,线程实现,编译器优化以及甚至调度程序的确切时序。
如果我这样做,我会编写产生高并发性的多线程测试,并确保我在多处理器实现上运行。然后我可能会观察有和没有volatile
的代码之间的差异。测试的结果仍然是不确定的。
答案 2 :(得分:1)
编译器可能没有缓存计数器,因为它是一个类范围的变量。所以写入是在内存中。
如果要测试易失性和非易失性写/读..
public class VolatileExperiment
{
private int counter ;
private volatile int volatile_counter;
public void Counter()
{
new Thread( new Runnable(){
public void run()
{
++counter;
++volatile_counter;
//print
}
}).start();
new Thread( new Runnable(){
public void run()
{
++counter;
++volatile_counter;
//print
}
}).start();
//print counter
//print volatile
}
}
使用volatile确保编译器不优化代码,因此写入在内存中完成,而不是在线程内存中完成。因此,您应该看到volatile_counter
已更新..而counter
可能不会受到影响