Tag: monitor

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.

Two methods synchronized on the same monitor accessed by two threads

package com.bawi.threads;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TwoSynchronizedMethodOnSameMonitor {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(TwoSynchronizedMethodOnSameMonitor.class);
    
    public static void main(String[] args) throws InterruptedException {
        LOGGER.debug("Started");
        
        Thread t1 = new Thread(() -> {
            LOGGER.debug("Started");
            
            // we explicitly sleep 10 ms in main thread for thread t1 to enter synchronized method sychronizedSleep1 first
            sychronizedSleep1(3000);
            LOGGER.debug("Finished");
        });
        t1.start();
        sleepMillis(10); // wait 10 ms so thread t1 enters synchronized sychronizedSleep1 method first

        /* Main thread cannot enter synchronizedSleep2 as thread t1 is already in synchronized method sychronizedSleep1
           that owns the same shared monitor (TwoSynchronizedMethodOnSameMonitor.class) as synchronizedSleep2. 
           So main thread needs to wait 3s till thread t1 leave sychronizedSleep1.
           After that time main thread can eventually enter synchronizedSleep2. 
        */

        synchronizedSleep2(2000); 
        LOGGER.debug("Finished");
    }

    public static synchronized void sychronizedSleep1(int sleepMillis) {
        LOGGER.debug("synchronized sleep1");
        sleepMillis(sleepMillis);
    }

    public static synchronized void synchronizedSleep2(int sleepMillis) {
        LOGGER.debug("synchronized sleep2");
        sleepMillis(sleepMillis);
    }

    public static void sleepMillis(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

/* 
2015-10-19 17:35:23,158|main    |Started
2015-10-19 17:35:23,210|Thread-0|Started
2015-10-19 17:35:23,210|Thread-0|synchronized sleep1

2015-10-19 17:35:26,210|Thread-0|Finished
2015-10-19 17:35:26,210|main    |synchronized sleep2

2015-10-19 17:35:28,210|main    |Finished
*/