execute Thread.interrupt() Object.notify() at the same time, why does has two results?

Viewed 112
public class WaitNotifyAll {
    private static volatile Object resourceA = new Object();

    public static void main(String[] args) throws Exception {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resourceA) {
                    try {
                        System.out.println("threadA begin wait");
                        resourceA.wait();
                        System.out.println("threadA end wait");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Thread threaB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resourceA) {
                    System.out.println("threadC begin notify");
                    threadA.interrupt();
                    resourceA.notify();
                }
            }
        });

        threadA.start();

        Thread.sleep(1000);

        threaB.start();

        System.out.println("main over");
    }
 }

There are two possible result here:

  1. throws InterruptedException

  2. normal termination

why?

I don't understand. when threadA is interruptted ,result should throws InterruptedException. but sometimes execute this program, it can normal finish.

environment: java8, mac

2 Answers

Because of reordering. In normal termination compiler reordered instruction interrupt and notify, interruption invokes on working thread and no interrupted exception throws. Try to forbid reordering with reading volatile variable and you always get interrupted exception.

public class WaitNotifyAll {
private static volatile Object resourceA = new Object();

public static void main(String[] args) throws Exception {
    Thread threadA = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (resourceA) {
                try {
                    System.out.println("threadA begin wait");
                    resourceA.wait();
                    System.out.println("threadA end wait");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });

    Thread threaB = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (resourceA) {
                System.out.println("threadC begin notify");
                threadA.interrupt();
                System.out.print(resourceA);
                resourceA.notify();
            }
        }
    });

    threadA.start();

    Thread.sleep(1000);

    threaB.start();

    System.out.println("main over");
}

}

Related