java中,每个对象都拥有一个监视器,也就是锁。监视器(monitor)乍一听比较抽象,举个例子来说,它有点像一个厕所,假设厕所一次只能容下一个人,那么这个厕所就可以说是监视器了,监视器(厕所)监视着上厕所的每一个人,每次只允许一个人进入厕所,进入之后则会把厕所锁上,防止其它人再进入,其它人要想进入厕所则必须等待上一个人上完厕所才能进入。wait()方法的作用是:在拥有某个对象(暂时称之为lock)的锁(也就是监视器)的情况下,调用lock.wait()方法的线程当会等待,直到另外的某个线程再次调用lock.notify()或lock.notifyAll()。另外lock.notify()也并不总是可靠的,假如当前监视器上等待的线程不止一个,则另外某个线程调用一次lock.notify()方法时,只会唤醒一个调用了lock.wait()的线程。

下面我们来看一个例子,第一个是Thread1:

package com.test.thread;

public class Thread1 extends Thread {
    
    private final Object lock;
    
    public Thread1(Object lock){
        this.lock = lock;
        this.setName("thead1");
    }

    @Override
    public void run() {
        synchronized (lock) {
            try {
                System.out.println(getName() + " start.");
                lock.wait();
                System.out.println(getName() + " end.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

 

接下来是Thread2:

 

 

package com.test.thread;

public class Thread2 extends Thread {
    
    private final Object lock;
    
    public Thread2(Object lock){
        this.lock = lock;
        this.setName("thead2");
    }

    @Override
    public void run() {
        synchronized (lock) {
            try {
                System.out.println(getName() + " start.");
                Thread.sleep(100);
                lock.notify();
                System.out.println(getName() + " end.");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 

main方法:

/**
     * @param args
     */
    public static void main(String[] args) {
        Object o = new Object();
        //Object o2 = new Object();
        Thread1 t1 = new Thread1(o);
        Thread2 t2 = new Thread2(o);
        t1.start();
        t2.start();
    }

 

执行上面的程序输出:

 

thead1 start.
thead2 start.
thead2 end.
thead1 end.

首先启动两个线程,执行thead1时获得对象lock上的监视器(也就是锁),然后在thead1上调用了lock.wait(),它导致thread1线程处于等待状态,同时它也会释放lock上面的锁;接着thead2开始执行,它获得thread1释放的锁,然后调用lock.notify(),这会唤醒一个在此监视器上等待的一个线程,这时只有一个线程在等待,那就是thread1,这时thread1又恢复到可运行状态,它会和thread2一起竞争CPU资源,也就是说后面两句的输出顺序是不确定的,取决于谁获得CPU的执行时间。

 

假如我们使用的对象不是同一个会怎么样呢?我们将main方法代码更改一下:

 1 /**
 2      * @param args
 3      */
 4     public static void main(String[] args) {
 5         Object o = new Object();
 6         Object o2 = new Object();
 7         Thread1 t1 = new Thread1(o);
 8         Thread2 t2 = new Thread2(o2);
 9         t1.start();
10         t2.start();
11     }

 

这时只输出了:

thead1 start.
thead2 start.
thead2 end.

thread2一直处于等待状态,这是因为我们的两个线程同步时使用的不是同一个锁,thread2使用的o2,调用o2.notify()并不会唤醒thread1,因为thread1在o上面等待。