I am trying to follow the ReentrantLock Example in Java, Difference between synchronized vs ReentrantLock kind of tutorial. And I have a demo started with -ea
on as
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();
}
}
}
When using ReentrantLock
as the second method getCountUsingLock
, I will get java.lang.AssertionError
but when I commented them out to use synchronized
, it would be okay.
Considering its ReentrantLock, I removed the CountLock
defined in the class and using local lock as following, but it still not work.
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();
}
}
What's the missed point here?
Any help will be appreciated ;)
Kind of fool of myself.
It's working like that because I was actually locking on different objects.
private static synchronized int getCount()
is equal to
private static synchronized (ReentrantLockZero.class) int getCount()
while new ReentrantLock();
is always a new object and there is no way to eliminate the race condition using different locks.
So fool of me, it's easily fixed by the following demos
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();
}
}
}
Why the synchronized
work? Because then there is only one lock the two methods are locking on so the race condition resolved directly.
Kind of easily fooled by the tutorial; shame on me ;(