Aya1
Aya1

Reputation: 49

wait() isn't interrupted by notifyAll()

I've made the following code sample, which tests wait() and notifyAll() of the same locked object. Receiver thread is waiting on the locked object, while Sender thread activates the notifyAll().

public class MonitorState {

    private static complexObj lock = new complexObj();

    public static void main(String[] args) {
        writeLog("Main - \tLocker name = " + lock.getName());
        writeLog("Main - \tLocker code = " + lock.getCode());
        try {
            Thread receiver = new Receiver();
            Thread sender = new Sender();

            receiver.start();
            sender.start();

            Thread.sleep(5000);
            writeLog("Main - \tLocker name = " + lock.getName());
            writeLog("Main - \tLocker code = " + lock.getCode());
        }
        catch (Exception e) {
            writeLog(e.getMessage());
            e.printStackTrace();
        }
    }

    private static void writeLog(String msg) {
        Date time = new Date(System.currentTimeMillis());
        SimpleDateFormat  df = new SimpleDateFormat("HH:mm:ss.S");
        System.out.println(df.format(time) + " " + msg);
    }

    // locking object
    private static class complexObj {
        private String name = "complexObj";
        private Integer code = 0;

        public complexObj() {
        }

        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Integer getCode() {
            return code;
        }
        public void setCode(Integer code) {
            this.code = code;
        }
    }

    private static class Receiver extends Thread {
        public Receiver() {
        }

        @Override
        public void run() {
            int timeout = 100;
            try{
                synchronized (lock) {
                    writeLog("Receiver - Waiting for " + timeout + " ms.");
                    lock.wait(timeout);
                }
            }
            catch (InterruptedException e) {
                writeLog("Receiver - Interrupted.");
            }
            writeLog("Receiver - Timed out.");
            writeLog("Receiver - Locker code = " + lock.getCode());
            if (lock.getCode() == 0) {
                writeLog("Receiver - Setting values into the locker.");
                lock.setName("Receiver");
                lock.setCode(2);                
            }

        }
    }

    private static class Sender extends Thread {
        public Sender() {
        }

        @Override
        public void run() {
            synchronized (lock) {
                try {
                    int sleepTime = 3000;
                    writeLog("Sender - \tSleeping for " + sleepTime + " ms.");
                    sleep(sleepTime);
                    writeLog("Sender - \tSetting values into the locker.");
                    lock.setName("Sender");
                    lock.setCode(1);
                    lock.notifyAll();
                }
                catch (InterruptedException e) {
                    writeLog("Sender - \tInterrupted.");
                }
            }
        }
    }

}

The output is:

 16:17:52.191 Main -    Locker name = complexObj
 16:17:52.237 Main -    Locker code = 0
 16:17:52.237 Receiver - Waiting for 4000 ms.
 16:17:52.238 Sender -  Sleeping for 3000 ms.
 16:17:55.238 Sender -  Setting values into the locker.
 16:17:55.238 Receiver - Timed out.
 16:17:55.238 Receiver - Locker code = 1
 16:17:57.237 Main -    Locker name = Sender
 16:17:57.237 Main -    Locker code = 1

My question is - why isn't the Receiver reaches to the "Interrupted" message?

Second question: If I change the wait time for the Receiver thread to 100ms, the output is:

16:31:21.522 Main -     Locker name = complexObj
16:31:21.571 Main -     Locker code = 0
16:31:21.571 Receiver - Waiting for 100 ms.
16:31:21.571 Sender -   Sleeping for 3000 ms.
16:31:24.572 Sender -   Setting values into the locker.
16:31:24.572 Receiver - Timed out.
16:31:24.572 Receiver - Locker code = 1
16:31:26.571 Main -     Locker name = Sender
16:31:26.571 Main -     Locker code = 1

Looking at the timestamp, you see that it took 3 seconds for the Receiver to get to the "Timed out" message, and not 100ms as it should have. 3 seconds is the time the sender is active before using the notifyAll(). Can you please explain why 3 seconds and not 100ms?

Upvotes: 0

Views: 159

Answers (2)

cichystefan
cichystefan

Reputation: 328

When it comes to the second question - the Sender sleeps for 3 seconds, keeping the lock. If you want a thread to cease execution and release the lock, use wait(3000) instead of sleep(3000).

Upvotes: 0

StenSoft
StenSoft

Reputation: 9619

When the lock is notified, the method wait just returns, no exception is thrown. InterruptException is thrown when the thread is interrupted using Thread.interrupt(), not when the lock is notified.

Upvotes: 1

Related Questions