[英]Java threading issue?
我想知道为什么结果不是40万。有两个线程为什么会被阻止?
class IntCell {
private int n = 0;
public int getN() {return n;}
public void setN(int n) {this.n = n;}
}
class Count extends Thread {
private static IntCell n = new IntCell();
@Override public void run() {
int temp;
for (int i = 0; i < 200000; i++) {
temp = n.getN();
n.setN(temp + 1);
}
}
public static void main(String[] args) {
Count p = new Count();
Count q = new Count();
p.start();
q.start();
try { p.join(); q.join(); }
catch (InterruptedException e) { }
System.out.println("The value of n is " + n.getN());
}
}
为什么这样有问题?
因为增加变量的方法实际上并不是增加它的原子操作,所以:
它们不是原子操作的3个操作,您应该给我们一个synchronized
块,或者改用AtomicInteger
。
使用synchronized
块,它将类似于:
synchronized (n) {
temp = n.getN();
n.setN(temp + 1);
}
使用AtomicInteger
您将需要如下重写代码:
class IntCell {
private final AtomicInteger n = new AtomicInteger();
public int getN() {return n.get();}
public void incrementN(int n) {this.n.addAndGet(n);}
}
for (int i = 0; i < 200000; i++) {
n.incrementN(1);
}
使用AtomicInteger
的方法是非阻塞的,因此它将更快
这里的问题是您考虑了比赛条件。 考虑循环内的块:
temp = n.getN();
n.setN(temp + 1);
代码上下文在获取当前N的时间和递增当前N的时间之间切换,从而设置了“旧”值。 解决此问题的一种方法是确保循环的内部部分在同步块中运行:
for (int i = 0; i < 200000; i++) {
synchronized (n) { / Here!
temp = n.getN();
n.setN(temp + 1);
}
}
当两个线程同时访问一个对象时,它们会相互干扰,结果是不确定的。 例如,假设p
读取n
的值并得到0,然后q
读取相同的值并也得到0,然后p
将value设置为1, q
也将其设置为1(因为它仍然认为它具有值0)。 现在,即使两个计数器都将其“递增”一次, n
的值也将增加1。 您需要使用synchronized
块来确保计数器不会相互干扰。 有关更多信息,请参见https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.