wait(),notify() 和 notifyAll()使用及原理

    简述:在上一篇日志中,分析了synchronized关键字,其底层是对对象加锁,通过锁来限制同一时刻只有一个线程来访问同步块,而wait方法是让当前线程失去对锁的拥有权,让出锁,让其他线程进入,又有monitor监视器是属于对象的,那么wait方法及notify也是数据对象的,他们都是对某一个对象的锁的获取和释放。基于以上,可以看出来对于wait方法是建立在锁之上的,notify/notifyAll 方法也是建立在锁的基础上,他们会唤醒在当前锁对象上面等待的线程,直到当前线程执行完synchronized方法体以后,会唤醒在当前锁上等待的线程。所以对notify/notifyAll 方法的调用最好是在synchronized方法的最后一步,执行完notify/notifyAll 之后就会释放掉锁。

先来看一个列子

public class NotifyTest {
    public synchronized void testWait() {
        System.out.println(Thread.currentThread().getName() + " Start----");
        try{
            wait();
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " End------");
    }

    public static void main(String[] args) throws Exception{
        final NotifyTest test = new NotifyTest();
        for(int i = 0; i < 5; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    test.testWait();
                }
            }).start();
        }
        Thread.sleep(1000);
        synchronized (test){
            test.notify();
        }
       Thread.sleep(3000);

        System.out.println("---------------我是分割线-------------");

        synchronized (test){
            test.notifyAll();
        }
    }
}

下面这个程序的输出结果是:

Thread-0 Start----
Thread-1 Start----
Thread-3 Start----
Thread-4 Start----
Thread-2 Start----
Thread-0 End------
---------------我是分割线-------------
Thread-2 End------
Thread-4 End------
Thread-3 End------
Thread-1 End------

在notify方法调用时,只会去唤醒等待池中的一个线程,notifyAll是会唤醒所有的等待线程。

如果没有被唤醒的线程,将一直处于等待池中,由于我们的线程没有设置成daemon线程,所以处于等待池中的线程如果一直没有被唤醒,那么我们的程序将不会停止。

总结:

1、如果一个线程调用了wait方法,那么该线程首先需要获取到这个对象的锁(换句话说,一个线程如果调用了某个方法的wait方法,那么该wait方法必须是在synchronized方法中的)

2、如果一个线程调用了wait方法,那么当前线程就会释放掉线程的锁。(这个是wait和sleep方法不同的地方)

3、在java中一个对象,会有两个池(锁池,等待池),如果一个线程调用了wait方法,那么该线程进入该对象的等待池中(释放锁),如果未来的某一刻,另外一个线程调用了这个对象的notify方法,或者notifyAll,那么在等待池中的线程就会起来进入该对象的锁池中,参与到获取锁的竞争当中,如果获取锁成功,将沿着wait方法之后的代码执行(这就是为什么生产者消费者中,使用while来判断状态,而不是if)

notify和notifyAll方法并不会去释放当前锁对象,而是通过moniterexist来释放,也就是说,当前所述的代码块在执行结束之后,回去释放掉锁,只有在锁被释放掉之后,等待池中的线程进入到锁池,去竞争锁资源。

以上是关于wait,notify及notifyAll方法的介绍。如有错误,欢迎指正~

参考:

Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)

JVM源码分析之Object.wait/notify实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值