Java Articles

Advertisement

Java ReentrantLock Interruption Example

by Ram Satish

Share

In this article we will see how to acquire a ReentrantLock in an interruptible and non-interruptible mode. When a thread fails to acquire the lock, it gets added to a waiting queue. It can be unblocked either by the thread holding the lock or by interrupting it.

Non-Interruptible Mode

When we call ReentrantLock.lock(), we acquire lock in a non-interruptible mode which means even if the thread waiting in queue is interrupted or unparked, it is going to simply retry acquiring the lock. This goes on, resulting in blocking and unblocking of the thread till it acquires the lock.

Acquiring Non-Interruptible Lock
Acquiring Non-Interruptible Lock

Interruptible Mode

Advertisement

We can try acquiring lock in exclusive interruptible mode using ReentrantLock.lockInterruptibly() in which case if the thread in waiting is interrupted by some other thread it will result in InterruptedException thus there won’t be any retry. If the thread is unparked as a result of release of lock then it is going to retry acquiring lock.

Acquiring Non-Interruptible Lock
Acquiring Non-Interruptible Lock

Interruptible Mode Example

AcquireLockRunnable acquires lock in either interruptible or non-interruptible mode based on the parameter passes in to the constructor. Once the thread acquires the lock, it sleeps for few seconds and releases the lock in the finally block. The first thread that acquires the lock, holds the lock a bit longer than the other threads so that the threads trying to acquire gets added to the queue.

AcquireLockRunnable:

package com.javarticles.threads;

import java.util.concurrent.locks.ReentrantLock;

public class AcquireLockRunnable implements Runnable {
int id;
boolean interruptable;
ReentrantLock lock;

AcquireLockRunnable(ReentrantLock lock, int id) {
this(lock, id, true);
}

AcquireLockRunnable(ReentrantLock lock, int id, boolean interruptable) {
this.lock = lock;
this.id = id;
this.interruptable = interruptable;
}

public void run() {
print("Try lock");
try {
if (interruptable) {
lock.lockInterruptibly();
} else {
lock.lock();
}
} catch (InterruptedException e) {
print("Acquiring lock failed due to " + e);
return;
}
print("Got lock(" + id + ")");
try {
try {
if (id == 1) {
Thread.sleep(3000);
} else {
Thread.sleep(2500);
}
} catch (InterruptedException e) {
print("Sleep interrupted");
}
} finally {
lock.unlock();
print("Unlocked(" + id + ")");
}
}

static void print(String p) {
System.out.println(Thread.currentThread().getName() + ": " + p);
}
}

In our first example, we acquire the lock in an interruptible mode. In method lockAndInterrupt(), we start multiple threads. Each thread tries to acquire the lock. After the first thread is created and started, we sleep for couple of seconds so that the first thread gets a chance to acquire the lock. We pass an instance of AcquireLockRunnable as the Runnable. We then start the other threads which end up waiting in queue till they acquire the lock or are interrupted.

ReentrantLockInterruptableExample:

package com.javarticles.threads;

import java.util.concurrent.locks.ReentrantLock;
import static com.javarticles.threads.AcquireLockRunnable.print;

public class ReentrantLockInterruptableExample {
private static ReentrantLock lock = new ReentrantLock();
private boolean interruptable;

ReentrantLockInterruptableExample() {
this(true);
}

ReentrantLockInterruptableExample(boolean interruptable) {
this.interruptable = interruptable;
}

public static void main(String[] args) throws InterruptedException {
ReentrantLockInterruptableExample lockInterruptable = new ReentrantLockInterruptableExample();
lockInterruptable.lockAndInterrupt();
}

void lockAndInterrupt() throws InterruptedException {
Thread firstThread = new Thread(new AcquireLockRunnable(lock, 1,
interruptable), "Thread(1)");
firstThread.start();
Thread.sleep(2000);
Thread[] others = new Thread[6];
for (int i = 2; i < 8; i++) {
others[i - 2]= new Thread(new AcquireLockRunnable(lock, i,
interruptable), "Thread(" + i + ")");
others[i - 2].start();
}
print("Interrupt threads");
for (int i = 0; i < 6; i++) {
Thread.sleep(500 * i / 2);
print("Interrupt " + others[i].getName());
others[i].interrupt();
}
}
}

Once all the threads are started, we interrupt threads in the order in which we have started. You can see from the below output, ‘Thread(1)’ acquires the lock first and remain threads try to acquire but fail till the first the thread doesn’t release the lock. Moment ‘Thread(1)’ release the lock, ‘Thread(5)’ ends up acquiring the lock as ‘Thread(2)’, ‘Thread(3)’ and ‘Thread(4)’ were interrupted which results in java.lang.InterruptedException so they no more contest for the lock. ‘Thread(5)’ is interrupted and then it releases the lock which is then acquired by ‘Thread(6)’.

Output:

Thread(1): Try lock
Thread(1): Got lock(1)
Thread(2): Try lock
Thread(3): Try lock
Thread(4): Try lock
main: Interrupt threads
main: Interrupt Thread(2)
Thread(5): Try lock
Thread(6): Try lock
Thread(2): Acquiring lock failed due to java.lang.InterruptedException
Thread(7): Try lock
main: Interrupt Thread(3)
Thread(3): Acquiring lock failed due to java.lang.InterruptedException
main: Interrupt Thread(4)
Thread(4): Acquiring lock failed due to java.lang.InterruptedException
Thread(1): Unlocked(1)
Thread(5): Got lock(5)
main: Interrupt Thread(5)
Thread(5): Sleep interrupted
Thread(5): Unlocked(5)
Thread(6): Got lock(6)
main: Interrupt Thread(6)
Thread(6): Sleep interrupted
Thread(6): Unlocked(6)
Thread(7): Got lock(7)
main: Interrupt Thread(7)
Thread(7): Sleep interrupted
Thread(7): Unlocked(7)

Non-Interruptable Mode Example

I our next example, we acquire the lock in a non-interruptible mode which is the default mode.

ReentrantLockInterruptableExample:

package com.javarticles.threads;

public class ReentrantLockIgnoreInterruptionExample {
public static void main(String[] args) throws InterruptedException {
ReentrantLockInterruptableExample lockInterruptable = new ReentrantLockInterruptableExample(false);
lockInterruptable.lockAndInterrupt();
}
}

As you can see below, even though the threads are interruptes, it doesn’t result in java.lang.InterruptedException, instead they simply try again to acquire the lock.

Output:

Thread(1): Try lock
Thread(1): Got lock(1)
Thread(2): Try lock
Thread(3): Try lock
Thread(4): Try lock
main: Interrupt threads
Thread(6): Try lock
Thread(5): Try lock
Thread(7): Try lock
main: Interrupt Thread(2)
main: Interrupt Thread(3)
main: Interrupt Thread(4)
Thread(1): Unlocked(1)
Thread(2): Got lock(2)
Thread(2): Sleep interrupted
Thread(2): Unlocked(2)
Thread(3): Got lock(3)
Thread(3): Sleep interrupted
Thread(3): Unlocked(3)
Thread(4): Got lock(4)
Thread(4): Sleep interrupted
Thread(4): Unlocked(4)
Thread(6): Got lock(6)
main: Interrupt Thread(5)
main: Interrupt Thread(6)
Thread(6): Sleep interrupted
Thread(6): Unlocked(6)
Thread(5): Got lock(5)
Thread(5): Sleep interrupted
Thread(5): Unlocked(5)
Thread(7): Got lock(7)
main: Interrupt Thread(7)
Thread(7): Sleep interrupted
Thread(7): Unlocked(7)

Download the source code

This was an example about interrupting a thread trying to acquire a ReentrantLock.

You can download the source code here: javaReentrantLockInterruptableExample.zip

Share

Advertisement

Related

Advertisement

Latest

Advertisement