I’m trying to understand what makes the lock in concurrency so important if one can use synchronized (this). In the dummy code below, I can do either:
- synchronized the entire method or synchronize the vulnerable area (
synchronized(this){...}) - OR lock the vulnerable code area with a ReentrantLock.
Code:
private final ReentrantLock lock = new ReentrantLock();
private static List<Integer> ints;
public Integer getResult(String name) {
.
.
.
lock.lock();
try {
if (ints.size()==3) {
ints=null;
return -9;
}
for (int x=0; x<ints.size(); x++) {
System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
}
} finally {
lock.unlock();
}
return random;
}
A ReentrantLock is unstructured, unlike
synchronizedconstructs — i.e. you don’t need to use a block structure for locking and can even hold a lock across methods. An example:Such flow is impossible to represent via a single monitor in a
synchronizedconstruct.Aside from that,
ReentrantLocksupports lock polling and interruptible lock waits that support time-out.ReentrantLockalso has support for configurable fairness policy, allowing more flexible thread scheduling.ReentrantLockmay also be more scalable, performing much better under higher contention. You can read more about this here.This claim has been contested, however; see the following comment:
When should you use
ReentrantLocks? According to that developerWorks article…One final aspect that’s gonna become more relevant in the near future has to do with Java 15 and Project Loom. In the (new) world of virtual threads, the underlying scheduler would be able to work much better with
ReentrantLockthan it’s able to do withsynchronized, that’s true at least in the initial Java 15 release but may be optimized later.