如下面给出的代码我可以使用密集锁(监视器)用于我的count
变量,并且通过使Thread
方法成为同步方法,一次只能访问单个synchIncrement()
。然后O / P应该是20000
但仍然会有一些时差值。
为什么?
public class SynchBlockThread {
private int count = 0;
private synchronized void synchIncrement() {
count++;
}
public static void main(String[] args) {
SynchBlockThread sBT = new SynchBlockThread();
sBT.doWork();
}
private void doWork() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i<10000; i++) {
synchIncrement();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i<10000; i++) {
synchIncrement();
}
}
});
t1.start();
t2.start();
try {
t1.join();
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
}
}
相当难以发现。
在doWork()
方法结束时,你加入Thread t1
两次,所以Thread t2
在结果打印时仍然在做它的工作。
在代码中表达它:
try {
t1.join();
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
应该是
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized方法可以正常工作。问题是你不是在等第二个Thread
。 count
可以在第二个线程终止之前打印,所以你也应该添加t2.join();
:
try {
t1.join();
t2.join();
} catch (InterruptedException e) { ... }
让我们考虑一个更有趣的方法版本:
private void doWork() throws InterruptedException {
final int n = 2;
final CountDownLatch latch = new CountDownLatch(n);
final ExecutorService service = Executors.newFixedThreadPool(n);
final Runnable task = () -> {
for (int i = 0; i < 10000; i++) {
synchIncrement();
}
latch.countDown();
};
for (int i = 0; i < n; ++i) {
service.execute(task);
}
latch.await();
service.shutdown();
System.out.println(count);
}
我介绍了一个固定大小的ExecutorService
不能自己创建线程。我写了一个CountDownLatch
来知道所有任务何时完成执行,所以我可以关闭服务并打印结果。