为什么在演示中同步工作时ReentrantLock不起作用?

时间:2019-03-30 05:03:54

标签: java java-8 synchronized reentrantlock

我正在尝试遵循ReentrantLock Example in Java, Difference between synchronized vs ReentrantLock这种教程。我有一个以-ea开头的演示,

public class ReentrantLockZero {
    private static ReentrantLock CountLock = new ReentrantLock();
    private static int count = 0;
    private static final int RESULT_COUNT = 10_000;

    public static void main(String... args) throws Exception {
        ThreadPoolExecutor threadPoolExecutor = getMyCachedThreadPool();
        for (int i = 0; i < RESULT_COUNT; ++i) {
            threadPoolExecutor.submit(ReentrantLockZero::getCount);
            threadPoolExecutor.submit(ReentrantLockZero::getCountUsingLock);
        }
        threadPoolExecutor.shutdown();
        threadPoolExecutor.awaitTermination(10, TimeUnit.SECONDS);
        assert count == RESULT_COUNT * 2;
    }

    private static synchronized int getCount() {
        count++;
        System.out.println(Thread.currentThread().getName() + " counting in synchronized: " + count);
        return count;
    }

    private static int getCountUsingLock() {
        CountLock.lock();
        try {
            count++;
            System.out.println(Thread.currentThread().getName() + " counting in lock: " + count);
            return count;
        } finally {
            CountLock.unlock();
        }
    }
}

使用ReentrantLock作为第二种方法getCountUsingLock时,我会得到java.lang.AssertionError,但是当我注释掉它们以使用synchronized时,这是可以的。

考虑到其 Re entrantLock,我删除了在类中定义的CountLock并按以下方式使用本地锁,但仍然无法正常工作。

private static int getCountUsingLock() {
    ReentrantLock countLock = new ReentrantLock();
    countLock.lock();
    try {
        count++;
        System.out.println(Thread.currentThread().getName() + " counting in lock: " + count);
        return count;
    } finally {
        countLock.unlock();
    }
}

这里遗漏了什么?

任何帮助将不胜感激;)

1 个答案:

答案 0 :(得分:2)

那种傻瓜。

之所以这样工作,是因为我实际上锁定了其他对象

private static synchronized int getCount()

等于

private static synchronized (ReentrantLockZero.class) int getCount()

new ReentrantLock();始终是一个新对象,无法使用不同的锁来消除race condition

我这个傻瓜,可以通过以下演示轻松修复

public class ReentrantLockZero {
    private static ReentrantLock CountLock = new ReentrantLock();
    private static int synchronisedCount = 0;
    private static int lockedCount = 0;
    private static final int RESULT_COUNT = 10_000;

    public static void main(String... args) throws Exception {
        ThreadPoolExecutor threadPoolExecutor = getMyCachedThreadPool();
        for (int i = 0; i < RESULT_COUNT; ++i) {
            threadPoolExecutor.submit(ReentrantLockZero::getSynchronisedCount);
            threadPoolExecutor.submit(ReentrantLockZero::getCountUsingLock);
        }
        threadPoolExecutor.shutdown();
        threadPoolExecutor.awaitTermination(10, TimeUnit.SECONDS);
        assert synchronisedCount == RESULT_COUNT;
        assert lockedCount == RESULT_COUNT;
    }

    private static synchronized int getSynchronisedCount() {
        synchronisedCount++;
        System.out.println(Thread.currentThread().getName() + " counting in synchronized: " + synchronisedCount);
        return synchronisedCount;
    }

    private static int getCountUsingLock() {
        CountLock.lock();
        try {
            lockedCount++;
            System.out.println(Thread.currentThread().getName() + " counting in lock: " + lockedCount);
            return lockedCount;
        } finally {
            CountLock.unlock();
        }
    }
}

synchronized为什么起作用?因为那时只有一个锁,所以这两种方法都处于锁定状态,因此竞争条件可以直接解决。

容易被本教程所欺骗;对我感到羞耻;(