Question

What do you actually use for this method lockInterruptibly? I have read the API however it's not very clear to me. Could anybody express it in other words?

Was it helpful?

Solution 2

The logic is the same as for all interruptible blocking methods: it allows the thread to immediately react to the interrupt signal sent to it from another thread.

How this particular feature is used is up to the application design. For example, it can be used to kill a contingent of threads in a pool which are all waiting to aquire a lock.

OTHER TIPS

lockInterruptibly() may block if the the lock is already held by another thread and will wait until the lock is aquired. This is the same as with regular lock(). But if another thread interrupts the waiting thread lockInterruptibly() will throw InterruptedException.

Try to understand this concept through below code example.

Code Sample:

package codingInterview.thread;

import java.util.concurrent.locks.ReentrantLock;

public class MyRentrantlock {

    Thread t = new Thread() {

        @Override
        public void run() {

            ReentrantLock r = new ReentrantLock();
            r.lock();

            System.out.println("lock() : lock count :" + r.getHoldCount());

            interrupt();
            System.out.println("Current thread is intrupted");
            r.tryLock();
            System.out.println("tryLock() on intrupted thread lock count :" + r.getHoldCount());
            try {
                r.lockInterruptibly();
                System.out.println("lockInterruptibly() --NOt executable statement" + r.getHoldCount());
            } catch (InterruptedException e) {
                r.lock();
                System.out.println("Error");
            } finally {
                r.unlock();
            }

            System.out.println("lockInterruptibly() not able to Acqurie lock: lock count :" + r.getHoldCount());

            r.unlock();
            System.out.println("lock count :" + r.getHoldCount());
            r.unlock();
            System.out.println("lock count :" + r.getHoldCount());

        }

    };

    public static void main(String str[]) {
        MyRentrantlock m = new MyRentrantlock();
        m.t.start();

        System.out.println("");
    }

}

Output:

lock() : lock count :1
Current thread is intrupted
tryLock() on intrupted thread lock count :2
Error
lockInterruptibly() not able to Acqurie lock: lock count :2
lock count :1
lock count :0

Based on Evgeniy Dorofeev's answer, I just deliberately come up with such demo but I really I have no clue where is exactly, it could be used. Perhaps this demo could help a tad :)

private static void testReentrantLock() {
    ReentrantLock lock = new ReentrantLock();
    Thread thread = new Thread(() -> {
        int i = 0;
        System.out.println("before entering ReentrankLock block");
        try {
            lock.lockInterruptibly();
                while (0 < 1) {
                    System.out.println("in the ReentrankLock block counting: " + i++);
                }
        } catch (InterruptedException e) {
            System.out.println("ReentrankLock block interrupted");
        }
    });
    lock.lock(); // lock first to make the lock in the thread "waiting" and then interruptible
    thread.start();
    thread.interrupt();
}

Output

before entering ReentrankLock block
ReentrankLock block interrupted

A thread that uses lockInterruptibly() can be interrupted by another thread. So, invocation to lockInterruptibly() throws InterruptedException which can be caught, and useful stuff can be done within the catch block like releasing the held lock, so that the other thread that has caused the interrupt to happen can gain access to the released lock. Think of the case where you have a common data structure with the below read and write constraints:

  1. A single thread is responsible for writing to the common data structure.
  2. There is a single reader thread.
  3. When a write is in process, read should not be allowed.

To fulfil the above constraints, the reader thread can use lockInterruptibly() to gain access to the java.util.concurrent.locks.ReentrantLock. That means the reader thread can be interrupted any time amidst processing by the writer thread. Writer thread would have access to the reader thread instance, and writer can interrupt the reader. When the reader receives the interrupt, in the catch block of the InterruptedException, the reader should unlock the hold on the ReentrantLock and await notification from the writer thread to proceed further. The writer thread can acquire the same lock using tryLock method. Code snippet for the reader and writer threads is given below:

Common fields accessed by both reader and writer threads:

ReentrantLock commonLock = new ReentrantLock(); //This is the common lock used by both reader and writer threads.
List<String> randomWords = new ArrayList(); //This is the data structure that writer updates and reader reads from. 
CountDownLatch readerWriterCdl = new CountDownLatch(1); //This is used to inform the reader that writer is done.

Reader:

try {
        if(!commonLock.isHeldByCurrentThread())
            commonLock.lockInterruptibly();                     
         System.out.println("Reader: accessing randomWords" +randomWords);              
    } catch (InterruptedException e) {                      
            commonLock.unlock();
            try {
                    readerWriterCdl.await();
                } 
                catch (InterruptedException e1) {

                }
    }

Writer:

if(commonLock.isLocked() && !commonLock.isHeldByCurrentThread()) 
{

    readerThread.interrupt();
}
                        
boolean lockStatus = commonLock.tryLock();
if(lockStatus) {
   //Update the randomWords list and then release the lock.
   commonLock.unlock();
   readerWriterCdl.countDown();
   readerWriterCdl = new CountDownLatch(1);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top