简体   繁体   English

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

[英]Sharing variable between threads in JAVA

I have two threads doing calculation on a common variable "n", one thread increase "n" each time, another decrease "n" each time, when I am not using volatile keyword on this variable, something I cannot understand happens, sb there please help explain, the snippet is like follow: 我有两个线程对一个公共变量“ 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) What I am expecting is "n=0,called=2" after execution, but chances are the main thread can be blocked in the while loop; 1)我期望执行后为“ n = 0,称为= 2”,但是主线程可能会在while循环中被阻塞;

2) But when I uncomment this line, the program when as expected: 2)但是当我取消注释该行时,程序按预期进行:

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

3) I know I should use "volatile" on "called", but I cannot explain why the above happens; 3)我知道我应该在“被叫”上使用“易失性”,但是我无法解释为什么会发生上述情况;

4) "called" is "read and load" in working memory of specific thread, but why it's not "store and write" back into main thread after "long" while loop, if it's not, why a simple "print" line can make such a difference 4)“被调用”是特定线程工作存储器中的“读取和加载”,但是为什么在“ long” while循环之后不将其“存储并写入”主线程,如果不是,为什么简单的“打印”行可以有所作为

You have synchronized writing of data (in inc and dec), but not reading of data (in main). 您已同步写入数据(以inc和dec为单位),但尚未读取数据(以main为主)。 BOTH should be synchronized to get predictable effects. 两者都应同步以获得可预期的效果。 Otherwise, chances are that main never "sees" the changes done by inc and dec. 否则,main可能永远不会“看到” inc和dec所做的更改。

You don't know where exactly called++ will be executed, your main thread will continue to born new threads which will make mutual exclusion, I mean only one thread can make called++ in each time because methods are synchronized, and you don't know each exactly thread will be it. 您不知道确切执行被调用的++的位置,您的主线程将继续产生新的线程,这将导致相互排斥,我的意思是每次只能有一个线程可以执行被调用的++,因为方法是同步的,并且您不知道每个线程确切的线程将是它。 May be two times will performed n++ or n--, you don't know this, may be ten times will performed n++ while main thread reach your condition. 在主线程达到您的条件时,可能执行两次n ++或n--,您可能不知道,可能执行十次n ++。

and try to read about data race 并尝试阅读有关数据竞赛的信息

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

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

 System.out.println(n);

You need to synchronize access to called here: 你需要同步访问called这里:

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

I sugest to add getCalled method 我建议添加getCalled方法

private synchronized int getCalled() {
    return called;
}

and replace called != 2 with getCalled() != 2 并用getCalled() != 2替换called != 2 getCalled() != 2

If you interested in why this problem occure you can read about visibility in context of java memory model. 如果您对为什么会发生此问题感兴趣,可以阅读有关Java内存模型上下文中的可见性的信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM