为什么Volatile表现得很奇怪 [英] Why Volatile is behaving weirdly

查看:177
本文介绍了为什么Volatile表现得很奇怪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近遇到过volatile关键字这种奇怪的行为。据我所知,

I have experience this weird behavior of volatile keyword recently. As far as i know,


  1. 对变量应用volatile关键字以反映对$ b数据所做的更改$ b将一个线程的变量放到另一个线程上。

  1. volatile keyword is applied on to the variable to reflect the changes done on the data of the variable by one thread onto the other thread.

volatile关键字阻止在线程上缓存数据。

volatile keyword prevents caching of the data on the thread.

我做了一个小测试........

I did a small test........


  1. 我使用了一个名为count的整数变量,并使用了volatile关键字。

  1. I used an integer variable named count, and used volatile keyword on it.

然后做了两个不同的线程来将变量值增加到10000,所以最终结果应该是20000。

Then made 2 different threads to increment the variable value to 10000, so the end resultant should be 20000.

但事实并非如此,使用volatile关键字我没有得到20000,但是18534,15000等....有时20000。

但是虽然我使用了synchronized关键字,但它运行正常,为什么.... ??

任何人都可以解释一下volatile关键字的这种行为。

Can anyone please explain me this behaviour of volatile keyword.

我发布了我的具有volatile关键字的代码以及具有synchronzied关键字的代码。

i am posting my code with volatile keyword and as well as the one with synchronzied keyword.

以下代码与变量计数上的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);
    }
}

以下代码与synchronized关键字完美配合方法go()。

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);
    }
}


推荐答案

volatile 关键字不是同步原语。它只是防止在线程上缓存值,但它不会阻止两个线程同时修改相同的值并将其写回。

The volatile keyword is not a synchronization primitive. It merely prevents caching of the value on the thread, but it does not prevent two threads from modifying the same value and writing it back concurrently.

假设有两个线程来到他们需要递增计数器的时间点,现在设置为5.两个线程都看到5,从中取出6,并将其写回计数器。如果计数器不是 volatile ,则两个线程都可以假设它们知道值为6,并跳过下一次读取。然而,它是不稳定的,所以它们都会读回6,并继续递增。由于线程没有进入锁定步骤,​​您可能会在输出中看到与10000不同的值,但实际上几乎没有机会看到20000.

Let's say two threads come to the point when they need to increment the counter, which is now set to 5. Both threads see 5, make 6 out of it, and write it back into the counter. If the counter were not volatile, both threads could have assumed that they know the value is 6, and skip the next read. However, it's volatile, so they both would read 6 back, and continue incrementing. Since the threads are not going in lock-step, you may see a value different from 10000 in the output, but there's virtually no chance that you would see 20000.

这篇关于为什么Volatile表现得很奇怪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆