State of threads, locks, and conditions

1.2k Views Asked by At

In Java if a thread, t2, attempts to attain a lock, from synchronized, which is currently in use by another thread, t1, then t2 will switch from runnable to blocked. Correct? What about with ReentrantLocks?

If the thread t1 finishes using the lock, does t2 then automatically switch back to runnable or do you need to use notifyAll()? What about with ReentrantLock usage without a condition. If you aren't using a condition how do you inform the thread t2 that it should switch back to runnable? Is it ever wise, or even possible to use reentrant locks without a condition?

If this question has already been answered (I couldn't find it), I would be grateful if you would link it to me.

2

There are 2 best solutions below

5
On BEST ANSWER

It sounds like you're confusing the blocked and waiting states. Blocked means that the thread is trying to acquire the lock and can't so is stuck. Waiting means the thread is dormant; it's hanging out until it receives a notification, or until it otherwise comes back from waiting (timeout, if called with a timeout value, or spurious wakeup).

Once a lock becomes available the OS scheduler has to decide which blocked thread gets it. The thread it picks to get the lock becomes runnable.

So notify pertains to waiting threads, not blocked ones. A thread that has the lock but which has figured out it can't progress (it detects the condition it's waiting for isn't true) can call wait on that lock, releasing the lock and going dormant. You use notify to tell the scheduler to wake up any one thread that is waiting on the lock. Once the thread is woken up it has to reacquire the lock it previously released before it can exit the wait method.

The basic behavior of ReentrantLock is analogous to intrinsic locks, except that you can have multiple conditions with reentrant locks. Keep in mind ReentrantLock has its own separate methods to call (await and signal instead of wait and notify). You would use conditions with ReentrantLock when you want the threads to wait and get notified, with different conditions used so that threads will be waiting only on conditions relevant to them.

0
On

If a thread t2 attempts to synchronize on a lock that is currently in use by another thread t1 - for example by attempting to enter a synchronized block when t1 is already in a synchronized block on the same lock - then t2 will block, yes. This is also true for reentrant locks, including the ReentrantLock class; it should be noted that default locks are reentrant in Java (more on this later).

If t1 releases a default lock, such as by exiting the synchronized block, then t2 is unblocked; this is a feature of the language. However, if you are using a ReentrantLock, the thread holding the lock must explicitly call ReentrantLock.unlock() to release the lock, just as it must have called ReentrantLock.lock() to obtain the lock.

Note that "reentrant" refers to whether a single thread can "reenter" synchronized blocks, not to any interaction between threads. Reentrant locks can be locked again by threads that already hold the lock; nonreentrant locks cannot. Note that in Java, if a single thread obtains a reentrant lock more than once, it must release the lock the same number of times before other threads waiting for the lock are unblocked. For default locks, this happens naturally with nested synchronized blocks, possibly at different function call levels.