Java中的wait方法

以下的的代码都是从
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4

的阅读而来。

1.wait抛出IllegalMonitorStateException异常,表示当前的线程没有获得w的锁

package thread;

public class WaitTest2 {
    static class Wait{
        public Wait() {
            //
        }
    }

    static Wait w = new Wait();

    public static void main(String[] args) throws InterruptedException {
        //throw java.lang.IllegalMonitorStateException
        //because current method main is not lock w
        w.wait();        
    }
}

2.wait抛出IllegalArgumentException异常,给wait所传的参数错误

package thread;

public class WaitTest2 {
    static class Wait{
        public Wait() {
            //
        }
    }

    static Wait w = new Wait();

    public static void main(String[] args) throws InterruptedException {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }        

        synchronized(w) {
            //throw exception 
            //java.lang.IllegalArgumentException: nanosecond timeout value out of range
            //w.wait(1, 1000000);

            //throw exception
            //java.lang.IllegalArgumentException: timeout value is negative
            w.wait(-1);
        }
    }
}

3.正常的使用wait

package thread;

public class WaitTest2 {
    static class Wait{
        public Wait() {
            //
        }
    }

    static Wait w = new Wait();

    static class MessageLoop implements Runnable {
        public void run() {
            synchronized(w) {
                System.out.println("I will be waiting. and release the monitor " +this);
                try {
                    w.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("I wait finished. and get the monitor" + this);
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new MessageLoop(), "Thread1");
        t1.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized(w) {
            System.out.println("I got the monitor, and will notify "+ Thread.currentThread());
            w.notify();            
            System.out.println("I have been notified. and will release the monitor "+ Thread.currentThread());
        }
    }
}

以下是屏幕输出:

I will be waiting. and release the monitor
thread.WaitTest2$MessageLoop@6fbae5f5
I got the monitor, and will notify Thread[main,5,main]
I have been notified. and will release the monitor Thread[main,5,main]
I wait finished. and get the monitorthread.WaitTest2$MessageLoop@6fbae5f5

4. If a thread is both notified and interrupted while waiting, it may either:
return normally from wait, while still having a pending interrupt (in other
words, a call to Thread.interrupted would return true)

return from wait by throwing an InterruptedException

如果线程同时收到notify和interrupt,它可能会:

从wait正常返回,但是没有处理interrupt,这时,Thread.interrupted返回为真

在wait时异常退出

package thread;

public class WaitTest2 {
    static class Wait{
        public Wait() {
            //
        }
    }

    static Wait w = new Wait();

    static class MessageLoop implements Runnable {
        public void run() {
            synchronized(w) {
                System.out.println("I will be waiting. and release the monitor " +this);
                try {
                    w.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("I wait finished. and get the monitor " + this);
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new MessageLoop(), "Thread1");
        t1.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized(w) {
            System.out.println("I got the monitor, and will notify "+ Thread.currentThread());
            t1.interrupt();
            w.notify();            
            System.out.println("I have been notified. and will release the monitor "+ Thread.currentThread());
        }
    }
}

屏幕的输出如下:

I will be waiting. and release the monitor
thread.WaitTest2$MessageLoop@208c5a4f
I got the monitor, and will notify Thread[main,5,main]
I have been notified. and will release the monitor Thread[main,5,main]
I wait finished. and get the monitorthread.WaitTest2$MessageLoop@208c5a4f

这个是notify先到,所以没有处理interrupt.

I will be waiting. and release the monitor
thread.WaitTest2$MessageLoop@574f7121
I got the monitor, and will notify Thread[main,5,main]
I have been notified. and will release the monitor Thread[main,5,main]
I wait finished. and get the monitor thread.WaitTest2$MessageLoop@574f7121
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at thread.WaitTest2$MessageLoop.run(WaitTest2.java:17)
at java.lang.Thread.run(Thread.java:722)

这个interrupt先到,所以先处理interrupt

另外,我在第二种情况时,看到屏幕输出如下:

I will be waiting. and release the monitor
thread.WaitTest2$MessageLoop@6fbae5f5
I got the monitor, and will notify Thread[main,5,main]
I have been notified. and will release the monitor Thread[main,5,main]
java.lang.InterruptedExceptionI wait finished. and get the monitor
thread.WaitTest2$MessageLoop@6fbae5f5

at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at thread.WaitTest2$MessageLoop.run(WaitTest2.java:17)
at java.lang.Thread.run(Thread.java:722)

所以又有另外一个问题,System.out.println是线程安全的吗?
http://stackoverflow.com/questions/9459657/synchronization-and-system-out-
println
这个链接说是线程安全的,

但是为什么会出现一个println的内容会在另一个e.printStackTrace()中呢。尽管printStackTrace()方法中同步了OutputStream。

如下:

private void printStackTrace(PrintStreamOrWriter s) {
    // Guard against malicious overrides of Throwable.equals by
    // using a Set with identity equality semantics.
    Set<Throwable> dejaVu =
        Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
    dejaVu.add(this);

    synchronized (s.lock()) {
    ...
    }
}

5.See http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4 For
example, if a thread t is in the wait set for m, and then both an interrupt of
t and a notification of m occur,
there must be an order over these events. If the interrupt is deemed to have
occurred first,
then t will eventually return from wait by throwing InterruptedException, and
some other thread in the wait set for m
(if any exist at the time of the notification) must receive the notification.
If the notification is deemed to have occurred first,
then t will eventually return normally from wait with an interrupt still
pending.

package thread;

public class WaitTest2 {
    static class Wait{
        public Wait() {
            //
        }
    }

    static Wait w = new Wait();

    static class MessageLoop implements Runnable {
        public void run() {
            synchronized(w) {
                System.out.println("I will be waiting. and release the monitor " +this);
                try {
                    w.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("I wait finished. and get the monitor " + this);
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new MessageLoop(), "Thread1");
        t1.start();

        Thread t2 = new Thread(new MessageLoop(), "Thread2");
        t2.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized(w) {
            System.out.println("I got the monitor, and will notify "+ Thread.currentThread());
            t1.interrupt();
            w.notify();            
            System.out.println("I have been notified. and will release the monitor "+ Thread.currentThread());
        }
    }
}

屏幕输出如下:

I will be waiting. and release the monitor
thread.WaitTest2$MessageLoop@2ab6994f 线程一
I will be waiting. and release the monitor
thread.WaitTest2$MessageLoop@3a0b2771线程二
I got the monitor, and will notify Thread[main,5,main]
I have been notified. and will release the monitor Thread[main,5,main]
I wait finished. and get the monitor thread.WaitTest2$MessageLoop@3a0b2771
线程二正常结束
java.lang.InterruptedException
I wait finished. and get the monitor thread.WaitTest2$MessageLoop@2ab6994f
线程一抛出异常
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at thread.WaitTest2$MessageLoop.run(WaitTest2.java:19)
at java.lang.Thread.run(Thread.java:722)

这里是如果有多个线程在wait w变量,这时如果有一个线程先收到interrupt的话,它会抛出interrupt异常,

然后会将notify传递给别的线程,然它们去出来notify。