在JAVA中的线程之间共享变量

时间:2016-08-30 12:34:01

标签: java multithreading variables shared volatile

我有两个线程在公共变量上进行计算" n",一个线程增加" n"每一次,另一次减少" n"每次,当我在这个变量上没有使用volatile关键字时,我无法理解的事情发生了,请帮忙解释一下,该片段如下:

public class TwoThreads {

private static int n = 0;
private static int called = 0;

public static void main(String[] args) {

    for (int i = 0; i < 1000; i++) {
        n = 0;
        called = 0;

        TwoThreads two = new TwoThreads();
        Inc inc = two.new Inc();
        Dec dec = two.new Dec();
        Thread t = new Thread(inc);
        t.start();
        t = new Thread(dec);
        t.start();
        while (called != 2) {
            //System.out.println("----");
        }
        System.out.println(n);

    }
}

private synchronized void inc() {
    n++;
    called++;
}

private synchronized void dec() {
    n--;
    called++;
}

class Inc implements Runnable {
    @Override
    public void run() {
        inc();
    }
}

class Dec implements Runnable {
    @Override
    public void run() {
        dec();
    }
}

}

1)我期待的是&#34; n = 0,称为= 2&#34;执行后,但很可能在while循环中可以阻止主线程;

2)但是当我取消注释这一行时,该程序按预期进行:

//System.out.println("----");

3)我知道我应该使用&#34; volatile&#34; on&#34;叫&#34;,但我无法解释上述原因;

4)&#34;叫&#34;是&#34;读取并加载&#34;在特定线程的工作记忆中,但为什么它没有&#34;存储和写入&#34;在&#34; long&#34;之后回到主线程while循环,如果不是,为什么一个简单的&#34; print&#34;线可以产生这样的差异

3 个答案:

答案 0 :(得分:2)

您已经同步写入数据(在inc和dec中),但不能读取数据(在main中)。两者应该同步以获得可预测的效果。否则,主机永远不会“看到”由inc和dec完成的更改。

答案 1 :(得分:0)

你不知道确切地称为++将在哪里执行,你的主线程将继续生成新的线程,这将导致互斥,我的意思是每次只有一个线程可以调用++,因为方法是同步的,而你我不知道每一个都是正确的线程。可能会两次执行n ++或n--,你不知道这一点,当主线程达到你的条件时,可能会执行十次n ++。

并尝试阅读有关数据竞赛的信息

 while (called != 2) {
            //System.out.println("----");
 }

//.. place for data race, n can be changed

 System.out.println(n);

答案 2 :(得分:0)

您需要在此处同步called的访问权限:

while (called != 2) {
    //System.out.println("----");
}

我想添加getCalled方法

private synchronized int getCalled() {
    return called;
}

并将called != 2替换为getCalled() != 2

如果您对发生此问题的原因感兴趣,可以阅读有关java内存模型上下文中的可见性的内容。