我有一个简单的并发代码,可以递增共享变量。
两个线程将计数器分别递增 10,000,000 次并打印结果。
它工作正常(争用条件通过增量方法中的synchronized
解决(。
但是,在线程 A 完成递增后,线程 B 在线程 A 有机会打印其结果(应为 10,000,000(之前开始递增。我可以通过让线程 B 在开始自己的增量之前休眠 3 秒来解决它:
public class DogLatch {
private static Counter counter = new Counter();
public static void main(String[] args) throws Exception {
Thread a = new Thread(new A());
Thread b = new Thread(new B());
a.start();
b.start();
a.join();
b.join();
System.out.printf("counter: %,d", counter.getValue());
}
static class Counter {
private int i;
public void increment() {
synchronized (this) {
i++;
}
}
public int getValue() {return i;}
public void setValue(int i ) {this.i = i;}
}
static class A implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10_000_000; i++) {
counter.increment();
}
System.out.println("A done: " + counter.getValue());
}
}
static class B implements Runnable {
@Override
public void run() {
System.out.println("Go to school");
System.out.println("Walk dog");
try {
Thread.sleep(5000);
}
catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < 10_000_000; i++) {
counter.increment();
}
System.out.println("B done: " + counter.getValue());
}
}
}
会打印
Go to school
Walk dog
A done: 10000000
B done: 20000000
counter: 20,000,000
但是,如果我拒绝B
:
static class B implements Runnable {
@Override
public void run() {
System.out.println("Go to school");
System.out.println("Walk dog");
for (int i = 0; i < 10_000_000; i++) {
counter.increment();
}
System.out.println("B done: " + counter.getValue());
}
}
我得到
Go to school
Walk dog
A done: 17368068
B done: 20000000
counter: 20,000,000
输出。有没有办法在显示A done: 10000000
和B done: 10000000
的地方实现正确的输出,而无需在B
中诉诸Thread.sleep()
?
实际上,您的程序并没有真正执行太多并发处理。 您在线程 B 中等待 5 秒,而线程 A 增加到 10,000,000,然后 B 唤醒并继续。
如果您只是在单个线程中一个接一个地启动它们,则结果就是这样。
但是你知道它工作正常,因为最终结果总是 20,000,000 没有 sleep 语句。
如果您强制交替,您将失去使用线程的好处。 事实上,A 打印出不同的值,但最终计数是 20,000,000,这表明它工作得很好!