JAVA中线程间共享变量

JAVA中线程间共享变量,java,multithreading,variables,shared,volatile,Java,Multithreading,Variables,Shared,Volatile,我有两个线程对一个公共变量“n”进行计算,一个线程每次增加“n”,另一个线程每次减少“n”,当我没有在这个变量上使用volatile关键字时,发生了一些我无法理解的事情,sb那里请帮助解释,代码片段如下: public class TwoThreads { private static int n = 0; private static int called = 0; public static void main(String[] args) { for (int i = 0;

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

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();
    }
}
3) 我知道我应该在“called”上使用“volatile”,但我无法解释为什么会发生上述情况


4) “called”是特定线程的工作内存中的“read and load”,但为什么它在“long”while循环之后不“store and write”返回到主线程中呢?如果不是,为什么一个简单的“print”行可以产生如此大的差异呢?您已经同步写入了数据(inc和dec),但没有读取数据(main)。两者都应该同步以获得可预测的效果。否则,main可能永远不会“看到”inc和dec所做的更改。

您已同步写入数据(inc和dec),但未同步读取数据(main)。两者都应该同步以获得可预测的效果。否则,main可能永远不会“看到”inc和dec所做的更改。

您不知道调用的++将在何处执行,您的主线程将继续生成新线程,这些线程将进行互斥,我的意思是每次只有一个线程可以调用+,因为方法是同步的,你不知道每一根线都会是它。可能是两次将执行n++或n-,您不知道这一点,可能是十次将执行n++而主线程达到您的条件

并尝试阅读有关数据竞争的内容

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

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

 System.out.println(n);

你不知道被调用的++将在哪里执行,你的主线程将继续产生新的线程,这将产生互斥,我的意思是每次只有一个线程可以被调用+,因为方法是同步的,你不知道每个线程将被调用。可能是两次将执行n++或n-,您不知道这一点,可能是十次将执行n++而主线程达到您的条件

并尝试阅读有关数据竞争的内容

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

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

 System.out.println(n);

您需要在此处同步访问名为的

while (called != 2) {
    //System.out.println("----");
}
我建议添加
getCalled
方法

private synchronized int getCalled() {
    return called;
}
并替换调用的
2带有
getCalled()!=2


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

您需要同步对
的访问,该
称为

while (called != 2) {
    //System.out.println("----");
}
我建议添加
getCalled
方法

private synchronized int getCalled() {
    return called;
}
并替换调用的
2带有
getCalled()!=2


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

我认为使用Thread.sleep()方法而不是print()可以获得相同的效果。@victor您是对的,任何行都可以具有相同的效果,无法解释为什么,您无法控制任何线程何时执行;但是main将继续执行,当它完成时,另一个线程也将继续执行。这就是为什么应该使用Thread.join()停止main,直到线程的其余部分完成。(Thread.sleep()会做一段时间,但是join()会等到他们是芬兰语)我认为你可以使用Thread.sleep()方法而不是print()来获得相同的效果。@victor你是对的,任何一行都可以有相同的效果,不能解释为什么,你不能控制任何线程何时执行;但是main将继续执行,当它完成时,另一个线程也将继续执行。这就是为什么应该使用Thread.join()停止main,直到线程的其余部分完成。(Thread.sleep()将执行一段时间,但join()将等待,直到他们使用芬兰语)谢谢serega,我希望除了主线程之外,最多会有两个线程(inc和dec)在运行,因为否则它可能会在while循环中被阻塞,我循环1000次只是为了确定它是否有被阻塞的可能性。你不能确定while循环是否会阻塞,为此请使用called>2,因为当主线程到达while循环时,你的线程可以执行called++1000次,而你也不能确定,因为主线程可以在inc和dec线程调用++之前到达while循环,并且条件将失败,并且您将获得另一对新线程hanks serega,我预计除了主线程之外,最多会有两个线程(inc和dec)在运行,因为否则它可能会在while循环中被阻塞,我循环1000次只是为了确定它是否有被阻塞的可能性。你不能确定while循环是否会阻塞,为此请使用called>2,因为当主线程到达while循环时,你的线程可以执行called++1000次,而你也不能确定,因为主线程可以在inc和dec线程调用++之前到达while循环,并且条件将失败,您将获得另一对新线程。我需要查看您的整个代码,并且有很多不同的方法来实现这一点。基本上,将读写代码放在同步块中,并使用公共锁对象。因为main是静态方法,所以如果您想在那里阅读,您只能使用类对象或静态类级别变量。例如:
synchronized(TwoThreads.class){
/read n和/或called here
//write n和/或called here
}
我需要查看您的整个代码,还有很多不同的方法。基本上,将读写代码放在同步块中,并使用公共锁对象。因为main是静态方法,所以如果您想在那里阅读,您只能使用类对象或静态类级别变量。例如:
synchronized(TwoThreads.class){
/read n和/或called here
/write n和/或called here
}
talex谢谢,我会用谷歌搜索一下,但是为什么“System.out.println(----”;)可以得到这个任务呢