对象等待集如何解决“线程饿死”

我们知道多线程执行的时候是抢占式执行的,这样虽然大大提高了效率,但是也会导致许多问题出现,可以说是有利有弊。“线程饿死”就是其中一个弊端。

当我们在多个线程中加入锁之后,由于这些线程是抢占式并发执行的,这些线程就会去竞争这把锁,当某一个线程竞争到锁之后,如果由于缺乏某些条件导致CPU没有执行该线程,然后该线程释放锁之后还会继续去参与竞争。如果极端情况下一直都是该线程抢到锁,其他线程一直处于阻塞状态,就像没有抢到食物被饿死了一样,这就叫做“线程饿死”现象。这种现象会大大降低程序执行效率,因为其他线程长时间执行不了。

为了解决“线程饿死”现象,就引入了对象等待集——wait(),notify()。当第一次抢到锁的线程发现条件不成熟导致CPU无法执行该线程时,可以通过wait()方法释放锁然后进入阻塞队列,等待通知,等待期间不会再去参与竞争,也就不会去抢夺CPU资源,这样就不会出现“线程饿死”现象了。处于等待状态的线程直到其他线程中调用notify()方法告知其条件成熟之后才会继续参与锁的竞争。

wait()方法的工作过程

  1. 释放锁(得先有锁才能释放)
  2. 进入阻塞队列等待通知,这个过程可能会很久
  3. 当收到通知后,尝试重新获取锁,继续往下执行

下面我们以具体代码为例

public class ThreadDemo16 {//wait和notify方法的使用
    public static void main(String[] args) {
        Object o = new Object();
        Thread t1 = new Thread(){
            @Override
            public void run() {
              synchronized (o){//这个代表让当前线程竞争o这个对象的加锁状态。
                  try {
                      System.out.println(("等待开始"));
                      o.wait();
                      System.out.println(("等待结束"));
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
            }
        };
        //线程1用来手动进入等待队列,让程序运行起来之后,线程1会直接进入等待队列
        Thread t2 = new Thread(){
            @Override
            public void run() {
                synchronized (o){//谁先执行这段代码谁就先把指定对象的加锁状态设置为true,谁就抢到了锁。
                    System.out.println(("notify开始"));
                    o.notify();
                    System.out.println(("notify结束"));
                }
            }
        };
        t1.start();
        t2.start();
    }
    //线程2用来提醒线程1条件达成,可以继续执行线程了。
}

当等待开始之后,线程t1就会进入等待阻塞状态,直到线程t2中调用notify方法发出信号,然后线程t1中接到信号,尝试重新参与竞争,继续执行。此时线程t2还没有释放锁,所以线程t1此时会竞争失败。直到线程t2中执行完才有可能会成功。
需要注意得是wait()方法和notify()方法都是Object类中的方法,所以我们调用这两个方法都需要通过同一个对象。且都需要用synchrnoized关键字包裹起来,因为这两个方法都是需要在有锁的前提下。

在wait()方法的工作过程中,第一步释放锁和第二步等待通知这两个操作是原子性的,避免因为抢占式调度导致线程t1释放所之后,没有进入等待通知的状态就被线程t2抢到锁然后直接发出通知,这样线程t1就永远也收不到通知了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值