同步方法不能用作Lock ??为什么不锁定数量

时间:2018-09-03 19:45:05

标签: java multithreading thread-safety locking synchronize

如下面的代码所示,我对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);
    }
}

enter image description here

2 个答案:

答案 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)

同步方法正确执行其工作。问题在于您没有等待第二个Threadcount可以在第二个线程终止之前打印,因此您也应该添加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来知道所有任务何时完成执行,因此我可以关闭服务并打印结果。

相关问题