volatile关键字不会同步这些值

时间:2018-02-09 08:12:58

标签: multithreading synchronized volatile

下面的代码给出了如下结果:

Change listener
Change listener
Change listener
Incrementing MY_INT to:1
Incrementing MY_INT to:2
Got Change for MY_INT :1loc:0
Change listener
Change listener
Change listener
Change listener
Change listener
Change listener
Change listener
Change listener
Change listener
Incrementing MY_INT to:3
Change listener
Incrementing MY_INT to:4
Incrementing MY_INT to:5
Got Change for MY_INT :3loc:2
Change listener

我的问题是,因为我使用了volatile,所以MY_INT值应该反映为4或5.为什么它不反映。 Soemtimes,即使是那个价值我们得到1.请有人让我知道我哪里出错了。

public class VolatileTest {
    private static volatile int MY_INT = 0;

    public static void main(String[] args) {
        new ChangeListener().start();
        new ChangeMaker().start();
    }

    static class ChangeListener extends Thread {
        @Override
        public void run() {
            int local_value = MY_INT;
            while ( local_value < 5){
                if( local_value!= MY_INT){
                   System.out.println("Got Change for MY_INT :"+ MY_INT+"loc:"+local_value);
                     local_value= MY_INT;
                }
 System.out.println("Change listener");
            }
        }
    }

    static class ChangeMaker extends Thread{
        @Override
        public void run() {

            int local_value = MY_INT;
            while (MY_INT <5){
                 System.out.println("Incrementing MY_INT to:"+(local_value+1));
                MY_INT = ++local_value;

            }
        }
    }
}

2 个答案:

答案 0 :(得分:0)

这是可能发生的一件事:

 ChangeMaker                     ChangeListener
  ...                             ...
  MY_INT = 3
                                 Sees MY_INT != 2, calls println(...)
  MY_INT = 4
  MY_INT = 5
                                 local_value = MY_INT;    // 5
  all done (MY_INT==5)           all done (MY_INT==5)

更改侦听器可能会错过查看更改,因为测试local_value!=MY_INT不是原子的,具有作业local_value=MY_INT;

答案 1 :(得分:0)

除了一件事,你做得很好,你在访问volatile变量时没有添加同步。与原子不同,volatile变量可以保证您获得实际值而不会更改。我想在你的案例中使用原子作为AtomicInteger会更好。此外,您可以将int更改为Integer将额外synchronized添加到您的代码中,如下例所示。

public class VolatileTest {
private static volatile Integer MY_INT = 0;

public static void main(String[] args) {
    new ChangeListener().start();
    new ChangeMaker().start();
}

static class ChangeListener extends Thread {
    @Override
    public void run() {
        int local_value = MY_INT;
        while (local_value < 5) {
            // ! Here
            synchronized (MY_INT) {
                if (local_value != MY_INT) {
                    System.out.println("Got Change for MY_INT :" + MY_INT + "loc:" + local_value);
                    local_value = MY_INT;
                }
            }
            System.out.println("Change listener");
        }
    }
}

static class ChangeMaker extends Thread {
    @Override
    public void run() {

        int local_value = MY_INT;
        while (MY_INT < 5) {
            System.out.println("Incrementing MY_INT to:" + (local_value + 1));
            // ! And here
            synchronized (MY_INT) {
                MY_INT = ++local_value;
            }
        }
    }
}

}