同步方法不起锁?为什么不锁定计数

问题描述 投票:2回答:2

如下面给出的代码我可以使用密集锁(监视器)用于我的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

java multithreading thread-safety locking synchronize
2个回答
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
投票

synchronized方法可以正常工作。问题是你不是在等第二个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来知道所有任务何时完成执行,所以我可以关闭服务并打印结果。

© www.soinside.com 2019 - 2024. All rights reserved.