JAVA并发编程——2、wait/notify/notifyAll方法的使用以及注意事项

使用方法

在了解使用方法之前,要先知道一个概念——等待队列。
所有实例都拥有一个等待队列,它是在实例的wait方法执行后停止的线程的队列。

wait()等待方法

wait()方法的作用就是让调用线程暂停进入对应的实例的等待队列中
例如:
obj.wait()就是让当前线程停止并进入对象obj的等待队列中,
而通常的省略obj的写法:wait()实际上是等价于this.wait()。

notify()通知方法

notify()方法通知某对象等待队列中的一个线程从等待队列中取出。
例如:
obj.notify()就是让对象obj的等待队列中的一个线程出队(并不会指定是哪个线程),
同理省略obj写法:notify()等价于this.notify()。

notifyAll()通知全部方法

这个方法与notify()唯一的不同是notify()只唤醒一个线程而它唤醒全部线程。

注意事项

wait()方法注意事项

1、wait()不会自动唤醒,必须等到notify/notifyAll
2、调用wait()方法线程必须要持有锁
wait源码注释
这点要求我们要把wait方法写在被synchronized保护的同步代码中。
这样做的主要原因就是为了保证线程安全。而如果不这样做会产生什么问题呢

	class PCM{
    ArrayList<String> arrayList = new ArrayList<String>();

    public void add(String something){
        arrayList.add(something);
        notify();
    }

    public String take() throws InterruptedException {
        while(arrayList.isEmpty()){
            wait();
        }
        return arrayList.remove(0);
    }
}

一段典型的生产者消费者模型
这段代码可能发生的最大问题就是:

当调用take方法判断arrayList是否为空时得到了true也就是arrayList为空。而这时在进入wait等待前,调度器就暂停了这个线程。注意此时wait还没执行。

而后add开始执行,它将一些东西添加进了arrayList,并调用了notify。此时notify并不会产生任何作用。

最后调度器将暂停的take方法继续执行,就出现了问题 wait等待开始了。但这时就进入了永久的等待(如果只有一个生产者)

会发生这一切的原因就是while判断和wait等待并不是一个synchronized的操作或者说不是一个原子的操作。将判断与执行做了拆分在并发条件下就会产生很多意料之外的事情。

3、线程一进入等待队列会释放锁(和sleep()不同 sleep不会释放锁)

这里额外提一句wait和sleep的区别:
	1、wait要写在synchronized中,sleep没有要求
	2、sleep不会释放锁,wait会
	3、wait方法除非被notify/notifyAll唤醒不然会一直等待,
		而sleep要设置一个等待时间。(这可能就是自然醒和被人叫醒的区别吧#狗头)
	4、wait是Object类的方法,sleep是Thread类的方法

notify()/notifyAll()

1、要执行notify/notifyAll方法必须持有所调用实例的锁(与wait对应)
2、当等待队列中线程不只一个时,notify选择线程是否按照wait等待顺序来唤醒在虚拟机规范中并没有规定。所以不应该指望notify来做出正确的选择。
3、被notify和notifyAll唤醒的线程不会立即执行。(因为此时执行notify的线程还持有者锁)要等待持锁线程释放锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值