2

我只是想写一个竞争条件的例子:

MyParallelClass.java

public class MyParallelClass implements java.lang.Runnable {
    public int counter = 0;

    @Override
    public void run() {
        if (test.globalVar > 0) {
            for (int i = 0; i < 1000000; i++) {
                counter++;
            }
            test.globalVar--;
        }
    }
}   

测试.java

public class test {
    public static int globalVar;

    public static void main(String[] args) {
        globalVar = 1;

        MyParallelClass a = new MyParallelClass();
        MyParallelClass b = new MyParallelClass();

        new Thread(a).start(); // Thread A
        new Thread(b).start(); // Thread B

        System.out.println(globalVar);
    }
}   

我认为会发生的事情:

我认为0如果线程 A 在线程 B 启动之前完全执行,这可能会输出。

该变量test.globalVar也可以像这样被操纵:

Thread A                     -  Thread B  
checks if (globalVar > 0)
      looping ...               checks if (globalVar > 0)
      looping ...               execute all four bytecode commands of "test.globalVar--;"
      execute test.globalVar--;

所以 的值test.globalVar-1

因此,要么执行 if 语句之一,要么执行两者。

实际发生了什么:

我得到01作为主要方法的输出。为什么我得到0and1而不是0and -1

4

4 回答 4

3

您正在减少globalVar两次。最后的可能值为globalVar

  • -1- 如果一切正常并且两个线程在打印之前正确地减少了值

  • 0

    • 如果只有一个线程设法减少变量,而第二个线程在打印之前没有完成

    • 如果globalVar同时减少

  • 1

    • 如果System.out.println()设法在两个线程完成之前执行(很可能)。globalVar确实被修改了,但是在它已经被打印出来之后

    • 由于可见性问题main线程看到原始globalVar值,而不是由不同线程修改的值。您需要某种同步或volatile关键字来立即(或永远)查看其他线程所做的更改。

于 2012-07-30T19:37:54.840 回答
1

System.out.println(globalVar);

不等待线程完成。此时线程可能已完成,也可能未完成。因此,该值可以是01-1取决于两个线程是否都已完成、一个已完成或两者均未完成。

为了进行更好的测试,
-Thread.sleep()在线程中使用以确保存在延迟
- 在不同线程中使用不同的延迟以更好地可视化竞争条件。
- 您可能还想在线程中打印变量的值。这样,您就拥有三个线程(A、B 和主线程)并获得更好的可视化效果。

于 2012-07-30T19:39:15.793 回答
0

好问题。我认为您需要进行更多测试。:-)

您可以尝试将 Runnable 类中的循环更改为以随机数毫秒 (500-1000) 休眠。仅循环 10 次。看看您是否没有达到预期的比赛条件。

我认为大多数计算机都太快了。您的简单循环可能没有做足够的工作来导致线程切换。

我喜欢这类问题,因为我总是遇到这样的错误。

于 2012-07-30T19:37:15.600 回答
0

如果在任一线程递减该值之前打印该值,您可以获得 1。

于 2012-07-30T19:39:41.203 回答