并行编程2个共享变量运行的线程

时间:2016-07-13 09:21:00

标签: java multithreading concurrency parallel-processing

我有一个关于并发性的问题,我刚刚编写了一个运行2个线程的程序,其中包含以下指令:

Thread 1: increment by 1 the variable "num" till 1'000'000 with loop
Thread 2: same thing but decrementing

最后我收到了不良后果。是的,我知道我可以同步或尝试使用重入锁,但问题是我无法理解所有这些不同的不良结果背后的原因。

我的意思是我正在使用的操作是可交换的,因此我们不关心排序,所以如果这无关紧要,我们仍然应该获得0而不是这种情况!

有人可以向我解释一下所有计算背后会发生什么,这样我才能感受到,我能立即认出这种情况吗?

编辑: 由于我只是对理解主要概念感兴趣,所以认为没有必要放置代码。

代码:

class MyThread implements Runnable {
int id;
volatile static long num = 0;


MyThread(int id) {
    this.id = id;

public void run() {
    if (id == 0) {
            for (int j = 0; j < 100000; ++j)
                num++;}
    } else {
            for (int j = 0; j < 100000; ++j)
                num--;}

在此之后我创建了Threads并运行它们:

    MyThread p = new MyThread(0);
    MyThread q = new MyThread(1);
    Thread t = new Thread(p);
    Thread u = new Thread(q);
    t.start();
    u.start();
    try {
        t.join();
        u.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

EDIT2: 我现在理解这个概念,但我也想知道为什么将变量声明为volatile仍然会给我错误的结果?

EDIT3:我考虑过这个问题,我认为这是因为错误的交错仍然会带来问题!

2 个答案:

答案 0 :(得分:4)

如果递增/递减操作不是原子操作,则最终可能会出现这种行为 如果系统的其余部分在瞬间发生,则操作被视为原子。 (参见wikipedia)。

考虑以下情况:

  1. Thread 1读取变量n中的值x
  2. Thread 2读取变量n中的值x
  3. Thread 1将值递增并将其存储在变量x中,现在评估为n+1
  4. Thread 2递减值并将其存储在变量x中,现在在n-1进行求值。
  5. 但您想要的是变量x仍在n进行评估。

    我不知道java原语的具体情况,但似乎您可以使用AtomicInteger或使用synchronized方法来解决您的问题。

答案 1 :(得分:0)

只需将此字段标记为volatile即可。通过这种方式,您将获得安全访问,并且您将能够在多线程应用程序中更改它,而无需使用任何其他同步工具。