Kum*_*tra 8 java multithreading volatile synchronized
我最近经历过volatile关键字这种奇怪的行为.我所知道的,
volatile关键字应用于变量,以将一个线程对变量数据所做的更改反映到另一个线程上.
volatile关键字阻止在线程上缓存数据.
我做了一个小测试........
我使用了一个名为count的整数变量,并在其上使用了volatile关键字.
然后制作2个不同的线程将变量值增加到10000,因此最终结果应为20000.
但事实并非如此,使用volatile关键字我一直没有得到20000,而是18534,15000等......有时候是20000.
但是虽然我使用了synchronized关键字,但它工作得很好,为什么......?
任何人都可以解释我挥发性关键字的这种行为.
我发布带有volatile关键字的代码,以及带有synchronzied关键字的代码.
以下代码与变量计数上的volatile关键字行为不一致
public class SynVsVol implements Runnable{
volatile int count = 0;
public void go(){
for (int i=0 ; i<10000 ; i++){
count = count + 1;
}
}
@Override
public void run() {
go();
}
public static void main(String[] args){
SynVsVol s = new SynVsVol();
Thread t1 = new Thread(s);
Thread t2 = new Thread(s);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Total Count Value: "+s.count);
}
}
Run Code Online (Sandbox Code Playgroud)
以下代码与方法go()上的synchronized关键字完美匹配.
public class SynVsVol implements Runnable{
int count = 0;
public synchronized void go(){
for (int i=0 ; i<10000 ; i++){
count = count + 1;
}
}
@Override
public void run() {
go();
}
public static void main(String[] args){
SynVsVol s = new SynVsVol();
Thread t1 = new Thread(s);
Thread t2 = new Thread(s);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Total Count Value: "+s.count);
}
}
Run Code Online (Sandbox Code Playgroud)
Ada*_*dam 12
count = count + 1不是原子的.它有三个步骤:
这三个步骤交织在一起,导致不同的执行路径,导致不正确的值.使用AtomicInteger.incrementAndGet(),如果你想避免synchronized关键字来代替.
因此,尽管volatile关键字的行为与您所描述的几乎相同,但它仅适用于每个单独的操作,而不适用于所有三个操作.
该volatile关键字是不是原始的同步.它只是防止在线程上缓存值,但它不会阻止两个线程修改相同的值并同时将其写回.
假设有两个线程需要递增计数器,现在设置为5.两个线程都看到5,从中取出6,并将其写回计数器.如果计数器不是volatile,则两个线程都可以假设它们知道值为6,并跳过下一个读取.然而,它是不稳定的,所以它们都会读回6,并继续递增.由于线程没有进入锁定步骤,您可能会在输出中看到与10000不同的值,但实际上您几乎没有机会看到20000.