-1

I see in many tutorials for Reentrant lock, they create a new Reentrant lock and resource is injected, lock and unlock of reentrant lock is called in try/finally block. I don't understand the connection between this lock and resource which is used in the thread. Below is an example of tutorial on Reentrant lock

Resource code

public class Resource {

    public void doSomething(){
        //do some operation, DB read, write etc
    }
    
    public void doLogging(){
        //logging, no need for thread safety
    }
}

Resource being used in thread declaration code

public class ConcurrencyLockExample implements Runnable{

    private Resource resource;
    private Lock lock;
    
    public ConcurrencyLockExample(Resource r){
        this.resource = r;
        this.lock = new ReentrantLock();
    }
    
    @Override
    public void run() {
        try {
            if(lock.tryLock(10, TimeUnit.SECONDS)){
            resource.doSomething();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            //release lock
            lock.unlock();
        }
        resource.doLogging();
    }
}

Can someone explain me how this prevents multiple threads from accessing the given resource at same time resulting in race condition??? Is this reentrant lock creating a Object level lock or Class level lock in the resource???

  • `Resource` is just an object with a `doSomething()` method. `ReentrantLock` is just a lock object with additional capabilities; see [here](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html). – Robert Harvey May 23 '22 at 13:51
  • 1
    The way it prevents multiple threads from accessing the resource is this: `lock.tryLock()` returns `false`. – Robert Harvey May 23 '22 at 13:52
  • Not sure what you mean by "object level lock" or "class level lock". It's not `static` if that's what you mean. Each `ConcurrencyLockExample` object contains its own `ReentrantLock` object. Presumably, each ConcurrencyLockExample object can only handle one thread at a time, but you can have multiple such objects, each handling its own series of `run()` calls. – Robert Harvey May 23 '22 at 13:54
  • It is neither. It is a lock, period. – user207421 May 23 '22 at 23:59

1 Answers1

1

In one sense, a ReentrantLock is neither a class-level nor an object-level lock. In a more practical sense, it's the same as either of them.

Really, you should forget about "class level" and "object level" locking. Those are not useful distinctions.

You can use any object as the lock in a synchronized(lock){...} block. "Object level" locking simply means that, within some method of a class C, the object that you choose is an instance of the class; and "class level" means that you choose to use C.class as the lock object.

But, you can use other objects too,* and synchronized(lock) behaves in the same way no matter what object you choose for the lock.


* This is a pattern that often is used by experienced software developers:

public class C {
    private final Object lock = new Object();

    public MyType myMethod(...) {
        ...
        synchronized(lock) {
            ...
        }
        ...
    }
}

The reason for using a private object is that the author of some client code that uses class C potentially could use an instance of C as a lock. That wouldn't be a smart idea, but nothing prevents them from doing it. If two different authors chose to use the same object as a lock, there could be unforseen interactions (e.g., in the worst case, a deadlock.) But the author of class C averts that problem by using a lock object that is inaccessible to other classes.

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57