wait()方法和notify()方法使用时的注意事项

释放双眼,带上耳机,听听看~!
  • wait()方法和notify()方法在使用时都有一个前提条件,必须都要获取当前对象的锁。也就是说如果wait()方法和notify()方法在使用时没有获取到锁时,程序就会直接抛出异常。
/**
 * 管理用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestAdmin extends Thread {

    private Object lock;

    public RequestAdmin(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            System.out.println(String.format("start wait time: %s", System.currentTimeMillis()));
            lock.wait();
            System.out.println(String.format("end wait: %s",  System.currentTimeMillis()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
 * 用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestUser extends Thread {


    private Object lock;

    public RequestUser(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        System.out.println(String.format("start notify time: %s", System.currentTimeMillis()));
        lock.notify();
        System.out.println(String.format("end notify: %s", System.currentTimeMillis()));
    }
}
/**
 * 测试类
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:49
 * @since 1.0.0
 */
public class RequestRun {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        RequestAdmin requestAdmin = new RequestAdmin(lock);
        RequestUser requestUser = new RequestUser(lock);
        requestAdmin.start();
        for (int i = 3; i > 0; i--) {
            System.out.println(String.format("倒计时:%s", i));
            Thread.sleep(1000);
        }
        requestUser.start();
    }
}
start wait time: 1489730354433
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
倒计时:3
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:502)
	at RequestAdmin.run(RequestAdmin.java:21)
倒计时:2
倒计时:1
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
start notify time: 1489730357489
	at java.lang.Object.notify(Native Method)
	at RequestUser.run(RequestUser.java:21)

我们看程序出线了异常。原因是我们没有添加synchronized关键字,所以线程获取不到锁,而直接抛出的异常。

  • wait()方法在执行完成后,会立刻释放对象的锁,这时其它线程依然可以执行wait()方法所在的synchronized同步方法。而notify()方法在执行完成后不会立即释放对象的锁,直到这个线程的synchronized同步方法执行完时才会释放锁。
/**
 * 管理用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestAdmin extends Thread {

    private Object lock;

    public RequestAdmin(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            synchronized (lock) {
                System.out.println(String.format("start wait time: %s", System.currentTimeMillis()));
                lock.wait();
                System.out.println(String.format("end wait: %s",  System.currentTimeMillis()));
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
 * 测试类
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:49
 * @since 1.0.0
 */
public class RequestRun {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        RequestAdmin requestAdmin = new RequestAdmin(lock);
        RequestAdmin requestAdmin2 = new RequestAdmin(lock);
        requestAdmin.start();
        requestAdmin2.start();
    }
}
start wait time: 1489730791034
start wait time: 1489730791068

我们看两个线程都暂停了,这就说明两个线程都获得了执行,原因就是上面分析的一样,wait()方法在执行完会立即释放对象的锁,所以线程一执行完时,线程二就可以直接获取到锁并执行,所以输出是异步显示的。下面我们在看一下notify()方法的事例。

/**
 * 用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestUser extends Thread {


    private Object lock;

    public RequestUser(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        synchronized (lock) {
            System.out.println(String.format("start notify time: %s", System.currentTimeMillis()));
            lock.notify();
            System.out.println(String.format("end notify: %s", System.currentTimeMillis()));
        }
    }
}
/**
 * 测试类
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:49
 * @since 1.0.0
 */
public class RequestRun {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        RequestUser requestUser = new RequestUser(lock);
        RequestUser requestUser2 = new RequestUser(lock);
        requestUser.start();
        requestUser2.start();
    }
}
start notify time: 1489731048739
end notify: 1489731048790
start notify time: 1489731048790
end notify: 1489731048790

我们看线程是同步执行的。原因是notify()方法在执行后不会立刻释放对象的锁,所以线程一在执行notify()方法后,线程二虽然已经启动成功,但它获取不到当前对象的锁,因为线程一还没有将锁释放,所以线程二只能等待因为方法是synchronized同步方法,所以输出信息是同步执行的。

  • wait()方法的本质是将当前线程添加到等待队列中,它不是线程的结束,因为它还可以恢复。notify()方法的本质是将等待队列中某一个线程使它退出等待队列。但如果等待队列中的线程有很多,notify()方法也只是随机抽取一个线程让它退出等待队列。
/**
 * 管理用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestAdmin extends Thread {

    private Object lock;

    public RequestAdmin(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            synchronized (lock) {
                System.out.println(String.format("start wait time: %stthread: %s", System.currentTimeMillis(), Thread.currentThread().getName()));
                lock.wait();
                System.out.println(String.format("end wait: %stthread: %s", System.currentTimeMillis(), Thread.currentThread().getName()));
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
 * 用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestUser extends Thread {


    private Object lock;

    public RequestUser(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        synchronized (lock) {
            System.out.println(String.format("start notify time: %stthread: %s", System.currentTimeMillis(), Thread.currentThread().getName()));
            lock.notify();
            System.out.println(String.format("end notify: %stthread: %s", System.currentTimeMillis(), Thread.currentThread().getName()));
        }
    }
}
/**
 * 测试类
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:49
 * @since 1.0.0
 */
public class RequestRun {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        RequestAdmin requestAdmin = new RequestAdmin(lock);
        RequestAdmin requestAdmin2 = new RequestAdmin(lock);
        RequestAdmin requestAdmin3 = new RequestAdmin(lock);
        RequestUser requestUser = new RequestUser(lock);
        requestAdmin.start();
        requestAdmin2.start();
        requestAdmin3.start();
        Thread.sleep(1000);
        requestUser.start();
    }
}
start wait time: 1489732406580	thread: Thread-0
start wait time: 1489732406621	thread: Thread-2
start wait time: 1489732406622	thread: Thread-1
start notify time: 1489732407594	thread: Thread-3
end notify: 1489732407594	thread: Thread-3
end wait: 1489732407594	thread: Thread-0

我们看线程一已经被唤醒了,然后继续执行了synchronized同步方法里的内容。

线程状态图

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧