Can a synchronized block / method be interrupted?

While I know the theoretical differences between Re-EntrantLocks and synchronized

, I am confused below.

See this statement from the article on Javarevisited comparing and objects : synchronized

Lock

Another important difference between ReentrantLock and the synchronized keyword in Java is the ability to interrupt Thread while waiting for a lock. In the case of a synchronized keyword, a thread could be blocked waiting for a lock, for an indefinite period of time, and there was no way to control it. ReentrantLock provides a method called lockInterruptibly () that can be used to interrupt a thread when it is waiting for a lock. Similarly tryLock () with a timeout can be used to timeout if a lock is unavailable for a specified period of time.

As per the above statement, I tried to interrupt Thread waiting () by a synchronized method (like block waiting) and it threw InterruptedException. But this behavior is contrary to what is stated in the above statement.

// this method is called from inside run() method of every thread. 
public synchronized int getCount() {
        count++;
        try {
            Thread.sleep(3000);
            System.out.println(Thread.currentThread().getName() + " gets " + count);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return count;
}

....
....
t1.start();
t2.start();
t3.start();
t4.start();

t2.interrupt();

      

Here is the result I got:

Thread 1 gets 1
Thread 4 gets 2
Thread 3 gets 3  
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at locks.SynchronizedLockInterrupt.getCount(SynchronizedLockInterrupt.java:10)  
    at locks.SynchronizedLockInterrupt$2.run(SynchronizedLockInterrupt.java:35)  
    at java.lang.Thread.run(Unknown Source)  

      


I'm confused if my example is wrong or the quoted statement about synchronized () is wrong?

+4


source to share


4 answers


Without the rest of the code, this question cannot be fully answered. I think what confuses you here is that you are seeing this, although the code assumes that you cannot "interrupt" a thread that is blocked by a synchronized

lock, you see that your variable count

appears to be unaffected by the thread that is supposed to have entered this method ...

It is important to note that you can technically "interrupt" a blocked thread, as you can call interrupt()

on it and that will set the flag interrupted

. The fact that it Thread

has the interrupt flag set does not mean that it can no longer execute code. Simply put, when it moves on to the next code that checks for an interrupted state, that code is likely to generate InterruptedException

while clearing the flag at the same time. If the person who catches the exception intends to do more work, it is his (almost moral) responsibility to plant the flag or to throw it down.

So yes, in your example, you have an .sleep()

exception that was .sleep()

on entry, probably before the thread .sleep()

went to sleep, then you have a .sleep()

stack trace that confirms this.

An outstanding question that may confuse you; why then count

didn't mine grow if that code was resolved before the .sleep()

method .sleep()

?

The answer is that the variable has count

been incremented, you just don't see the result.

synchronized

in Java does not guarantee order and can lead to starvation, so t2

just was executed last and you never checked the counter before falling asleep to see that it was already3



So, to answer your question, the documentation is correct and the behavior is correct.

Interrupting a thread that is waiting "continuously" in Lock

, ReentrantLock

or a synchronized

block, will simply cause the thread to wake up and see if it is still allowed to acquire the lock, by whatever mechanism is set in the defining lock, and if it cannot park again until it will not be interrupted again or told that it can take the lock. When the thread can continue, it simply continues with the flag set interrupted

.

Unlike lockInterruptibly

where, in fact, if you are interrupted, you never acquire the lock, and instead you "interrupt" the attempts to acquire the lock and the request for the lock is canceled.

lock

and lockInterruptibly

can be mixed, using the same ReentrantLock

lock will manage the queue and skip requests that were made by the CANCELLED

operator finally

because they were interrupted while waiting for a lock.

Eventually:

  • You can almost always interrupt the stream.
  • Interrupt flag is usually cleared only in a stream with a code that documents which it resets the flag when the throwing InterruptedException

    , but not all the documents of this code ( lockInterruptibly

    in the ReentrantLock

    making, but it is not the same at AbstractQueuedSynchronizer

    that feeds the castle).
  • Interrupting a thread has different behavior depending on what it is doing at the moment;
    • A parked thread will not be parked and a flag will be set on it, usually then cleared
    • A thread waiting for a lock / synchronized block will eventually hit the code, but with the interrupt flag set
    • The thread waits for lockInterruptibly or get

      for the future, etc. will be unparked and behave like a documentary discarding the acquisition of the castle.
+2


source


If only a simple example was added to make it clear.

In your example, you have already acquired the lock, see your stack trace. The code is self-explanatory.



The problem with synchronized is that it is not a breakpoint when it lock.lockInterruptibly()

is. Note that it is lock.lock()

also not a breakpoint.

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Foo {

    public static void main(String[] args) throws InterruptedException {

        // for the example with synchronized
        Object monitor = new Object();
        // for the example with locks
        Lock lock = new ReentrantLock();

        // iam lazy, just use both lock and motitor for this example
        Thread one = new Thread(() -> {
            lock.lock();
            try {
                synchronized (monitor) {
                    System.out.println("Thread one entered monitor");
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        System.out.println("Thread one interrupted");
                        Thread.currentThread().interrupt();
                    }
                }
            } finally {
                lock.unlock();
            }
        });

// uncomment to use the monitor object
//        Thread two = new Thread(() -> {
//            synchronized (monitor) {
//                System.out.println("Thread two entered monitor");
//            }
//        });

        Thread two = new Thread(() -> {
            try {
                lock.lockInterruptibly();
                try {
                    System.out.println("Thread one entered lock");
                } finally {
                    lock.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println("Thread two interrupted while waiting for lock");
                Thread.currentThread().interrupt();
            }
        });

        // start thread one
        one.start();
        // wait for the thread to start, too lazy to implement notifications
        Thread.sleep(1000);

        // start thread two
        two.start();
        // interrupting will wait until thread one finished
        two.interrupt();
    }
}

      

0


source


synchronized

is an internal lock that is outside the control of the JDK.

Synchronization is built around an internal entity known as internal lock or monitor lock. (The API specification often refers to this entity simply as a "monitor".) Inherent locks play a role in both aspects of synchronization: providing exclusive access to the state of an object and establishing pre-appearance relationships , which are important for visibility.

When a thread calls a synchronized method, it automatically acquires an internal lock on that method object and releases it when the method returns. The unlocking occurs even if the return was caused by an unhandled exception .

In your example, you are actually interrupting sleep

as the JDK doc mentions .

If this thread is blocked when calling the methods wait (), wait (long), or wait (long, int) of the Object class or join (), join (long), join (long, int), sleep (long), or sleep (long, int), methods of this class, then its interrupt state will be cleared and it will receive InterruptedException.

Learn more about how it worksinterrupt()

.

Many methods that throw InterruptedException, such as sleep, are designed to cancel their current operation and return immediately when an interrupt is received.

0


source


You do not interrupt sync, you interrupt sleep()

.

-1


source







All Articles