wait和notify/notifyAll

基本用法

wait和notify/notifyAll都是Object的方法,wait()方法代表的是在占用否个锁之后(这个前提很重要),放弃这个锁进入阻塞状态。这句话在详细铺开说:

  1. 在占用否个所之后
    这说明wait方法一定是在Sychronized代码块之内使用
  2. 放弃这个锁进入阻塞状态
    之前说过线程的阻塞状态细分为 wait_time(通常是调用带有时间sleep和join方法),还有两个就是blocked和wait 每个对象都有两个池子或者叫队列,等待池和锁池,当竞争某个对象的锁没有成功就会进入到锁池队列(状态为blocked),随时竞争到锁就可以执行,当某个线程竞争到了锁之后调用这个锁对象的wait方法即放弃这个锁的持有,进入等待池(状态为waitting),这个池里的线程除非被notify/notifyAll调用(或者被中断唤醒),否则无法改变状态。当被notify/notifyAll唤醒后,则进入锁池队列准备再次竞争锁对象,状态变为(blocked)
  3. notify之后并不是立刻释放锁
    在一个线程调用了某个锁的notify、notifyAll之后不会立刻释放锁,一直到锁的代码块执行过后才会释放锁

死锁问题

首先要说明死锁的四要素

  • 互斥使用
    即资源是有限制的,当无法获取资源的线程只能阻塞,等待资源释放
  • 不可抢占
    除非是占用锁的线程主动放弃,否则其他线程无法抢占
  • 请求和保持
    通常死锁是两个以上的资源的问题导致,当一个线程抢占A对象之后再去抢占B对象所的时候保持着对A对象的占用
  • 循环等待
    线程1抢占到对象A,线程2抢占到对象B;之后线程1尝试抢占对象B,阻塞,线程2尝试抢占对象A,阻塞。

notify带来的死锁问题

简单的说,notify()只唤醒一个正在等待的线程,当该线程执行完以后施放该对象的锁,而没有再次执行notify()方法,则其它正在等待的线程则一直处于等待状态,不会被唤醒而进入该对象的锁的竞争池,就会发生死锁。
ps.严格来讲notify不是死锁,因为只有一个锁对象
网上好多例子都在拿生产者和消费者举例,终极来说就是一个前提是好多生产者和消费者都在等待区,生产者的逻辑是产品没有达到数量上限才会生产,否则等待(消费者消费产品即可)。但是生产者等待的时候唤醒的是等待池里的生产者而非消费者,导致死锁。

posted @ 2023-02-24 11:44  龙祭司  阅读(44)  评论(0)    收藏  举报