Force unlocking a reentrant lock - java

I have a reentrant lock which I am wrapping in a customized class for my own needs. However due to the nature of the application a thread holding the lock to the reentrant lock gets stuck (external failures) and fails to release the reentrant lock.
I am wondering if there is a method to explicitly unlock the reentrant lock? I know the API for Reentrant lock does not have such a method - however I was thinking of introducing a timer task which will unlock the Reentrant lock after a set period of time OR kill the thread which holds the reentrant lock.
Any other suggestions in trying to force unlock my reentrant lock? My solutions are pretty thus I ask.

Instead of unlocking externally, I would execute the blocking code in a separate thread and have it timeout
something like this
Future<MyTask>future = taskExecutor.submit(myTask)
try {
future.get(5,TimeUnit.Seconds);
...
}
catch (Exception e)
{
future.cancel(true); // attempt to interupt the thread
throw new Exception();
}

As per my comment, any lock should be wrapped around a try/finally block to ensure that the lock is released if something goes wrong
_lock.lock(); // will wait until this thread gets the lock
try
{
// critical section
}
finally
{
//releasing the lock so that other threads can get notifies
_lock.unlock();
}
This is demonstrated in the Lock Objects trail

Related

How does multiple threads acquire and release lock in synchronized methods and synchronized blocks in java?

How does the java thread acquire a lock on a monitor used in synchronized block or monitor used in synchronized methods?
I read on multiple posts that in case of biased locking this information is stored in the object header using CAS operation and in case of contended situation wait set queue/ monitor queue is used but eventually lock marked in the object header only.
If this is the case then how is lock released? How object is marked free for acquiring a lock by another thread? are wait and notify methods used internally for this? If this is the case then why is making monitor null inside the synchronized block does not throw any exception.
The below example works perfectly fine, I was expecting NullPointerException assuming the end of the synchronized block will try to mark lock property to free the lock.
Example:
Object monitor = new Object();
synchronized (monitor){
System.out.println("before null");
monitor =null;
System.out.println("after null");
}
System.out.println("successfully Exited");
In case of biased locking: if the lock is biased towards a certain thread, no CAS is needed; just a volatile write. Biased lock information is kept in the mark word of the object header. Biased locking is going to be removed from JDK 15.
If a lock is contended, the object-monitor is used for synchronization. By default the object monitor is deflated, but if there is contention or you do a wait/notify, then the monitor gets inflated and is attached to the object.
On Linux blocking behavior is implemented using a wait-queue. So when a thread needs to wait for a lock, it is removed from the scheduler and added to the wait queue. When a lock unlocks, the thread on the wait queue is reinserted back into the scheduler.
The reason why the code doesn't throw an exception is that the monitor is read only once when the synchronized block is entered.
PS: It could be that your lock get completely removed due to lock elision. If the JIT can provide no other thread can acquire that lock, there is no point in synchronizing.

Why does this function never terminate?

Why does the following function deadlock? In other words, why does it prevent anyone from obtaining, not only the write lock, but the read lock? Can't read locks be shared?
void testReadWriteLock() throws InterruptedException {
final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
// Other thread acquires read lock and never releases it.
new Thread(() -> lock.readLock().lock()).start();
Thread.sleep(100);
// Other thread attempts (and fails) to acquire write lock.
new Thread(() -> lock.writeLock().lock()).start();
Thread.sleep(100);
lock.readLock().lock(); // This blocks forever
}
I discovered an interesting property of ReentrantReadWriteLock: any attempt to acquire the write lock (even blocking) blocks all subsequent attempts to acquire read locks (except re-entrant attempts). At least, that's the case in Oracle's 1.8 JVM. There is a certain logic in prioritizing writes: it ensures that data is up-to-date.
You can have multiple threads obtain the read lock, but when the write lock is obtained, everyone else is blocked out. Since you never unlock anything, the final lock call in the method will never obtain the lock.

How to understand the wait and notify method in Java Thread?

I'm very confusing about these two descriptions:
"The wait method blocks the calling thread and gives up the monitor lock"
"The notify method unblocks one waiting thread but does not give up the monitor lock"
Here is my questions:
I know each object in Java has a lock, but what is the "monitor lock" means? is it the same as the oject's lock?
Why notify method needs to give up the monitor lock?
If I try to make a object waiting with the following code:
class simpleTask extends Thread
{
int waitingTime;
public simpleTask(int waitingTime)
{
this.waitingTime = waitingTime;
}
public void run()
{
synchronized(this) // this is a reference of current object
{
try {
this.wait(waitingTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Like the first description above, is that means the the current object is blocked by synchronized keyword, and then wait method releases the lock?
I know each object in Java has a lock, but what is the "monitor lock" means? is it the same as the object's lock?
Yes, they are the same thing. They are also occasionally called the object's "mutex" and the object's "primitive lock". (But when someone talks about Lock, they are talking about this Java interface ... which is a different locking mechanism.)
Why notify method needs to give up the monitor lock?
The notify method doesn't give up the lock. It is your code's responsibility to give up the lock (i.e. leave the synchronized block or return from the synchronized method) after the notify call returns.
Why is that necessary? Because any other thread that is currently waiting on that lock (in a wait(...) call) has to reacquire that lock before the wait call can complete.
Why did they design notify / wait like this? So that they can be used to implement condition variables.
Like the first description above, is that means the the current object is blocked by synchronized keyword, and then wait method releases the lock?
That is correct. When a thread calls someObject.wait() its lock on someObject is released ... and then reacquired (by the same thread) before the wait() call returns. Of course, in the meantime the lock someObject may have been acquired and released multiple times by other threads. The point is that when wait returns, the thread that called wait will have the lock.
Yes, the monitor lock is the same as the object's lock. If you do synchronized (object), that's the lock.
In your example, the current object will give up the lock while waiting, the wait() call gives up the lock. In another thread, notify() is called to wake the object up, and when the wait() call returns it will hold the lock again.
A monitor is a type of synchronization construct.
The reason that waiting gives up the lock is so that other threads can acquire the lock, such as other threads that might want to wait. Also: It's usual for the thread that's awakening other threads to lock before releasing any threads, to prevent a race condition.
For more about this, you should study condition variables (i.e. condvars).

Java lock and happend-before relation

I'm not sure if I'm interpreting the javadoc right. When using a ReentrantLock after calling the lock method and successfully gaining a lock, can you just access any object without any synchronized blocks and the happend-before relationship is magically enforced?
I don't see any connection between the ReentrantLock and the objects I'm working on, that's why it is hard to believe I can work on them safely. But this is the case, or am I reading the javadoc wrong?
If thread A has modified some object inside a code block CB1 guarded by the lock and then releases the lock, and thread B enters in a code block guarded by the same lock, then thread B will see the modifications done by thread A in the code block CB1.
If two threads read and write the same shared state, then every read and write to this state should be guarded by the same lock.
It's ... a (mutex) lock:
void myMethod()
{
myLock.lock(); // block until condition holds
try
{
// Do stuff that only one thread at a time should do
}
finally
{
myLock.unlock()
}
}
Only one thread can hold the lock at a time, so anything between the lock() and unlock() calls is guaranteed to only be executed by one thread at a time.
The relevant Oracle tutorial can be found here.
There's no magic in it. You're safe if, and only if, all threads accessing an object use the same lock - be it a ReentrantLock or any other mutex, such as a synchronized block.
The existence ReentrantLock is justified by that it provides more flexibility than synchronized: you can, for example, just try to acquire the lock - not possible with synchronized.

What is Upgrade/Downgrade of ReentrantReadWriteLock?

What is Upgrade/Downgrade of ReentrantReadWriteLock?
I see javadoc about Upgrade/Downgrade:
"Lock downgrading :
Reentrancy also allows downgrading from the write lock to a read lock, by acquiring the write lock, then the read lock and then releasing the write lock. However, upgrading from a read lock to the write lock is not possible."
And a sample provided:
class CachedData {
Object data;
volatile boolean cacheValid;
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// upgrade lock manually
rwl.readLock().unlock(); // must unlock first to obtain writelock
rwl.writeLock().lock();
if (!cacheValid) { // recheck
data = ...
cacheValid = true;
}
// downgrade lock
rwl.readLock().lock(); // reacquire read without giving up write lock
rwl.writeLock().unlock(); // unlock write, still hold read
}
use(data);
rwl.readLock().unlock();
}
}
I know it talks about the relation between readLock and writeLock, but I couldn't get the clear concept from the doc. Could you give me a little more explanation? Thanks!
I believe that in this context the idea of "upgrading" and "downgrading" is based on the idea that the reader lock is, in a sense, a "weaker" lock than the writer lock. When the write lock is acquired, no other threads can acquire the lock in any form, whereas with a reader lock any other thread can acquire the read lock if it wants to.
Here, "downgrading" the lock means that if you hold the write lock, you can switch down to holding just the read lock by acquiring the read lock, then releasing the write lock. This means that you can have a thread that starts off doing something critically important (something that would prevent other threads from reading), does its work, and then switches to the lower-priority lock (the read lock) without ever being without the lock. This allows you to hold the lock continuously without getting preempted.
However, the other way doesn't work - once you're holding the read lock, you can't "upgrade" to holding the more important write lock by trying to acquire the write lock. If you tried to do this, the thread would just block until it was interrupted.
Hope this helps!

Categories

Resources