如下面的代码所示,我对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);
}
}
答案 0 :(得分:4)
一个很难发现的人。
在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();
}
答案 1 :(得分:1)
同步方法正确执行其工作。问题在于您没有等待第二个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
来知道所有任务何时完成执行,因此我可以关闭服务并打印结果。