Interrupting Java thread when busy loop, blocked to access synchronized block and calling wait method

1. Interrupting busy thread

public class InterruptBusyThread {

    private static final Logger LOGGER = LoggerFactory.getLogger(InterruptBusyThread.class);

    public static void main(String[] args) throws InterruptedException {
        LOGGER.debug("Started");

        Thread thread = new Thread(() -> {
            LOGGER.debug("Started");
            for (long counter = 0; counter < 99999999999L; counter++) { // busy loop
            }
            LOGGER.debug("Finished, thread isInterrupted:" + Thread.currentThread().isInterrupted());
        });
        thread.start();

        TimeUnit.SECONDS.sleep(1);
        LOGGER.debug("Finished sleeping, interrupting busy thread ...");
        thread.interrupt();
        LOGGER.debug("Finished");
    }
}

Output:
2015-11-07 10:30:13,380|main |Started
2015-11-07 10:30:13,446|Thread-0 |Started

2015-11-07 10:30:14,447|main |Finished sleeping, interrupting busy thread …
2015-11-07 10:30:14,447|main |Finished

2015-11-07 10:30:52,958|Thread-0 |Finished, thread isInterrupted:true

Note the call thread.interrupt() did not make any effect apart from setting interrupted flag. Thread kept on running.

2. Interrupting thread blocked waiting to access synchronized block

public class InterruptThreadBlockedWaitingToAccessSynchronizedBlock {

    private static final Logger LOGGER = 
             LoggerFactory.getLogger(InterruptThreadBlockedWaitingToAccessSynchronizedBlock.class);

    public static void main(String[] args) throws InterruptedException {
        LOGGER.debug("Started");
        Object monitor = new Object();

        Thread thread = new Thread(() -> {
            LOGGER.debug("Started, about to sleep");
            sleepSeconds(1); //wait so that main thread get access to monitor first
            LOGGER.debug("Finished sleeping, about to enter synchronized block");

            synchronized (monitor) {
                LOGGER.debug("Entered synchronized block, thread isInterrupted:{}", 
                                 Thread.currentThread().isInterrupted());
            }

            LOGGER.debug("Finished");
        });
        thread.start();

        synchronized (monitor) {
            LOGGER.debug("Entered synchronized block, started sleeping");
            sleepSeconds(3); // wait 3s to make sure thread0 gets BLOCKED waiting for 
                             //monitor to access synchronized block
            LOGGER.debug("Interrupting thread waiting on monitor");
            thread.interrupt();
            sleepSeconds(3);
            LOGGER.debug("Leaving synchronized block");
        }

        LOGGER.debug("Finished");
    }

    private static void sleepSeconds(int seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Output:
2015-11-07 10:47:29,337|main |Started
2015-11-07 10:47:29,403|main |Entered synchronized block, started sleeping
2015-11-07 10:47:29,403|Thread-0 |Started, about to sleep

2015-11-07 10:47:30,404|Thread-0 |Finished sleeping, about to enter synchronized block

2015-11-07 10:47:32,404|main |Interrupting thread waiting on monitor

2015-11-07 10:47:35,404|main |Leaving synchronized block
2015-11-07 10:47:35,404|main |Finished
2015-11-07 10:47:35,404|Thread-0 |Entered synchronized block, thread isInterrupted:true
2015-11-07 10:47:35,404|Thread-0 |Finished

Note that interrupting Thread-0 BLOCKED waiting on monitor to get access to synchronized block

“Thread-0” #16 prio=5 os_prio=0 tid=0x0000000058b5d000 nid=0x1294 waiting for monitor entry [0x000000005acbf000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.bawi.interrupt.InterruptThreadBlockedWaitingToAccessSynchronizedBlock.lambda$0(InterruptThreadBlockedWaitingToAccessSynchronizedBlock.java:23)
– waiting to lock (a java.lang.Object)
at com.bawi.interrupt.InterruptThreadBlockedWaitingToAccessSynchronizedBlock$$Lambda$3/2046562095.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)

does not give any effect apart from only changing thread isInterrupted flag. The Thread-0 keeps on being BLOCKED waiting to access monitor.

3. Interrupting thread calling wait method

public class InterruptThreadWaitingCallingWaitMethod {

    private static final Logger LOGGER = 
                LoggerFactory.getLogger(InterruptThreadWaitingCallingWaitMethod.class);

    public static void main(String[] args) throws InterruptedException {
        Object monitor = new Object();

        LOGGER.debug("Started");
        Thread thread = new Thread(() -> {
            LOGGER.debug("Started, about to enter synchronized block");

            synchronized (monitor) {
                LOGGER.debug("Entered synchronized block and sleeping 3 seconds");
                try {
                    sleepSeconds(3); // sleep 3s to show that wait() released the lock for main thread
                    LOGGER.debug("Finished sleeping, about to call wait() that releases monitor lock");
                    monitor.wait(); // calling wait() must be in synchronized block otherwise 
                    // java.lang.IllegalMonitorStateException will be thrown

                    // wait() immediately releases the lock so other thread could enter synchronized 
                    // block ON THE SAME MONITOR lock and could send notify on that monitor

                    // current thread need wait to re-acquire the lock to execute next 
                    // instruction in the synchronized block
                } catch (Exception e) {
                    LOGGER.warn("Re-acquired monitor lock and logging exception in catch:", e);
                }
                LOGGER.debug("Leaving synchronized block");
            }

            LOGGER.debug("Finished");
        });
        thread.start();

        sleepSeconds(1); //wait so that thread0 access to monitor first
        LOGGER.debug("Finished sleeping, about to enter synchronized block");
        synchronized (monitor) {
            LOGGER.debug("Entered synchronized block, interrupting thread waiting on monitor");
            thread.interrupt();
            LOGGER.debug("Sleeping while holding the monitor lock so Thread0 remains calling wait()");
            sleepSeconds(3); 
            LOGGER.debug("Finished sleeping and leaving synchronized block");
        }

        LOGGER.debug("Finished");
    }

    private static void sleepSeconds(int seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Output:
2015-11-07 16:21:49,697|main |Started
2015-11-07 16:21:49,748|Thread-0 |Started, about to enter synchronized block
2015-11-07 16:21:49,748|Thread-0 |Entered synchronized block and sleeping 3 seconds

2015-11-07 16:21:50,749|main |Finished sleeping, about to enter synchronized block

2015-11-07 16:21:52,749|Thread-0 |Finished sleeping, about to call wait() that releases monitor lock
2015-11-07 16:21:52,749|main |Entered synchronized block, interrupting thread waiting on monitor
2015-11-07 16:21:52,749|main |Sleeping while holding the monitor lock so Thread0 remain calling wait()

2015-11-07 16:21:55,749|main |Finished sleeping and leaving synchronized block
2015-11-07 16:21:55,749|main |Finished
2015-11-07 16:21:55,750|Thread-0 |Re-acquired monitor lock and logging exception in catch:
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at com.bawi.interrupt.InterruptThreadWaitingCallingWaitMethod.lambda$0(InterruptThreadWaitingCallingWaitMethod.java:24)
at java.lang.Thread.run(Thread.java:745)
2015-11-07 16:21:55,752|Thread-0 |Leaving synchronized block
2015-11-07 16:21:55,752|Thread-0 |Finished

Note that thread0 fist accessed the monitor for synchronized block and sleeps 3 seconds to show that main thread needs to wait for the monitor. When thread0 finished sleeping then it calls monitor.wait() method that internally releases the monitor lock and puts the thread0 into WAITING state (waiting for monitor.notify() or monitor.notifyAll()). Thread0 is now disabled from CPU scheduling. As the monitor lock is released then main thread enters synchronized block and interrupts the thread0 so that threads0 is no longer waiting and proceeds to catch clause and next instructions.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s