// 上面尤其要注意一点,一个线程被唤醒不代表立即获取了对象的monitor(锁),
// 只有等调用完notify()或者notifyAll()并退出synchronized块,释放对象锁后,
// 其余线程才能获得锁,才可获得锁执行。

public class Test {
    public static Object object = new Object();
    public static void main(String[] args) {
        Thread1 thread1 = new Thread1(object);
        Thread2 thread2 = new Thread2(object);
        Thread3 thread3 = new Thread3(object);

        thread2.start();
        thread3.start();

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

        thread1.start();

    }

}


 class Thread1 extends Thread{
     private Object object;
     public Thread1(Object object){this.object = object;}

    @Override
    public void run() {
        synchronized (object) { // 获取对象锁,该代码块才有执行的机会,其他线程则无法执行被该对象锁住的代码块
//            object.notify();  // Thread2,Thread3只有一个线程被唤醒,并获得锁(object对象),执行代码块,释放锁,另外一个线程永远没有机会被唤醒
            object.notifyAll(); // Thread2,Thread3两个线程都被唤醒,但是每个时刻只有一个线程获得锁(object对象),执行完毕之后,
                                // 另一个线程获得锁,执行代码块,释放锁
            System.out.println("线程"+Thread.currentThread().getName()+"调用了object.notify()");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } // synchronized语句块执行完毕才释放锁
        System.out.println("线程" + Thread.currentThread().getName() + "释放了锁");
    }
}


class Thread2 extends Thread{
    private Object object;
    public Thread2(Object object){this.object = object;}

    @Override
    public void run() {
        synchronized (object) {
            try {
                System.out.println("线程" + Thread.currentThread().getName() + "sleep");
                object.wait();
//                object.notify();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println("线程"+Thread.currentThread().getName()+"获取到了锁");
        }
    }
}


 class Thread3 extends Thread{
     private Object object;
     public Thread3(Object object){this.object = object;}

    @Override
    public void run() {
        synchronized (object) {
            try {
                System.out.println("线程" + Thread.currentThread().getName() + "sleep");
                object.wait();
//                object.notify();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println("线程"+Thread.currentThread().getName()+"获取到了锁");
        }
    }
}