wait和notify/notifyAll
基本用法
wait和notify/notifyAll都是Object的方法,wait()方法代表的是在占用否个锁之后(这个前提很重要),放弃这个锁进入阻塞状态。这句话在详细铺开说:
- 在占用否个所之后
这说明wait方法一定是在Sychronized代码块之内使用 - 放弃这个锁进入阻塞状态
之前说过线程的阻塞状态细分为 wait_time(通常是调用带有时间sleep和join方法),还有两个就是blocked和wait 每个对象都有两个池子或者叫队列,等待池和锁池,当竞争某个对象的锁没有成功就会进入到锁池队列(状态为blocked),随时竞争到锁就可以执行,当某个线程竞争到了锁之后调用这个锁对象的wait方法即放弃这个锁的持有,进入等待池(状态为waitting),这个池里的线程除非被notify/notifyAll调用(或者被中断唤醒),否则无法改变状态。当被notify/notifyAll唤醒后,则进入锁池队列准备再次竞争锁对象,状态变为(blocked) - notify之后并不是立刻释放锁
在一个线程调用了某个锁的notify、notifyAll之后不会立刻释放锁,一直到锁的代码块执行过后才会释放锁
死锁问题
首先要说明死锁的四要素
- 互斥使用
即资源是有限制的,当无法获取资源的线程只能阻塞,等待资源释放 - 不可抢占
除非是占用锁的线程主动放弃,否则其他线程无法抢占 - 请求和保持
通常死锁是两个以上的资源的问题导致,当一个线程抢占A对象之后再去抢占B对象所的时候保持着对A对象的占用 - 循环等待
线程1抢占到对象A,线程2抢占到对象B;之后线程1尝试抢占对象B,阻塞,线程2尝试抢占对象A,阻塞。
notify带来的死锁问题
简单的说,notify()只唤醒一个正在等待的线程,当该线程执行完以后施放该对象的锁,而没有再次执行notify()方法,则其它正在等待的线程则一直处于等待状态,不会被唤醒而进入该对象的锁的竞争池,就会发生死锁。
ps.严格来讲notify不是死锁,因为只有一个锁对象
网上好多例子都在拿生产者和消费者举例,终极来说就是一个前提是好多生产者和消费者都在等待区,生产者的逻辑是产品没有达到数量上限才会生产,否则等待(消费者消费产品即可)。但是生产者等待的时候唤醒的是等待池里的生产者而非消费者,导致死锁。
本文来自博客园,作者:龙祭司,转载请注明原文链接:https://www.cnblogs.com/gaokunlong/p/17150765.html