我有一个关于并发性的问题,我刚刚编写了一个运行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:我考虑过这个问题,我认为这是因为错误的交错仍然会带来问题!
答案 0 :(得分:4)
如果递增/递减操作不是原子操作,则最终可能会出现这种行为 如果系统的其余部分在瞬间发生,则操作被视为原子。 (参见wikipedia)。
考虑以下情况:
Thread 1
读取变量n
中的值x
。Thread 2
读取变量n
中的值x
。Thread 1
将值递增并将其存储在变量x
中,现在评估为n+1
。Thread 2
递减值并将其存储在变量x
中,现在在n-1
进行求值。 但您想要的是变量x
仍在n
进行评估。
我不知道java原语的具体情况,但似乎您可以使用AtomicInteger
或使用synchronized
方法来解决您的问题。
答案 1 :(得分:0)
只需将此字段标记为volatile
即可。通过这种方式,您将获得安全访问,并且您将能够在多线程应用程序中更改它,而无需使用任何其他同步工具。