Actual use of lockInterruptibly for a ReentrantLock
Asked Answered
A

5

18

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?

Audraaudras answered 23/7, 2013 at 13:26 Comment(0)
A
8

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.

Anthropophagi answered 23/7, 2013 at 13:55 Comment(4)
As stated "it allows the thread to immediately react to the interrupt signal sent to it from another thread," does it mean, When thread calls lockInterruptibly(), will wait for interrupt signal from another thread unless lock is immediatley available to get hold of it?. The thread that sends interrupt signal holds the lock untill it signals interrupt?Lashing
Any thread can interrupt the thread, it doesn't need to be the one holding the lock.Anthropophagi
Java thread interrupts differ from hardware or operating system interrupts. Interrupt delivery is synchronous & non-preemptive rather than asynchronous & preemptive i.e., they don’t occur at an arbitrary point & don’t pause (& later resume) running code. A program must test for them explicitly. So, are you saying that, lockInterruptibly continuously tests for them explicitly?Ethelstan
@Ethelstan It doesn't have to continuously test for them because it either returns immediately or is suspended. If another thread raises its interrupted flag, it will be notified and when it resumes, it will throw the InterruptedExceptionAnthropophagi
J
15

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.

Jetty answered 23/7, 2013 at 13:59 Comment(1)
To put a finer point on it... lockInterruptibly() is identical to lock() unless your code calls interrupt() at some point.France
A
8

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.

Anthropophagi answered 23/7, 2013 at 13:55 Comment(4)
As stated "it allows the thread to immediately react to the interrupt signal sent to it from another thread," does it mean, When thread calls lockInterruptibly(), will wait for interrupt signal from another thread unless lock is immediatley available to get hold of it?. The thread that sends interrupt signal holds the lock untill it signals interrupt?Lashing
Any thread can interrupt the thread, it doesn't need to be the one holding the lock.Anthropophagi
Java thread interrupts differ from hardware or operating system interrupts. Interrupt delivery is synchronous & non-preemptive rather than asynchronous & preemptive i.e., they don’t occur at an arbitrary point & don’t pause (& later resume) running code. A program must test for them explicitly. So, are you saying that, lockInterruptibly continuously tests for them explicitly?Ethelstan
@Ethelstan It doesn't have to continuously test for them because it either returns immediately or is suspended. If another thread raises its interrupted flag, it will be notified and when it resumes, it will throw the InterruptedExceptionAnthropophagi
P
1

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
Pulsifer answered 21/8, 2018 at 2:56 Comment(1)
I think ReentrantLock r = new ReentrantLock(); should be be placed out of run block?Inexperienced
I
1

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);
}
Immedicable answered 3/8, 2021 at 9:12 Comment(1)
Incorrect or at least a very poor example. The lock being held interruptibly has nothing to do with the writer thread interrupting the reader thread. The reader thread can be interrupted in any case, and it's only the case of acquiring the lock which is affected by the lockInterruptibly(). But if only the reader and writer acquire the lock, then there's never a situation where the reader would be interrupted while waiting to acquire the lock (if the reader is waiting, the writer has the lock and won't interrupt the reader).Schleiermacher
F
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
Feint answered 19/5, 2019 at 10:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.