wait()--阻塞线程

上一节:进程、线程一张图

wait()方法阻塞线程

先说一下线程的几个状态,也称作线程的生命周期
线程分为五个生命周期,分别是:
创建 – 就绪 – 运行 – 阻塞 – 死亡

个人理解:
创建状态和普通对象被创建一样,只是声明这么一个东西
就绪状态下,线程可以参与锁的竞争,等待获取cpu的执行权
运行状态,那就是线程在执行了,可以理解为一个被cpu允许执行的方法
阻塞状态,就是线程无法主动参与锁的竞争,需要被线程调度器唤醒之后才被允许参与锁竞争
死亡状态,不存在于进程中了

再来看一张图:
在这里插入图片描述
线程A、B、C都需要操作对象O

在第一次锁的竞争中,线程A抢到了对象O的锁,那么线程B和线程C都需要等待线程A释放对象O的锁才可以去获取对对象O的操作权;

线程A在执行的过程中调用了对象O的wait()方法,此时线程A就释放了对象O的锁并释放了cpu的执行权,进入对象O的等待队列,线程A此时处于阻塞状态,这个时候线程B和线程C开始竞争,然后线程B抢到对象O的锁;

线程B在执行的过程中又调用了对象O的wait()方法,此时,线程B也释放cpu的执行权和对象O的锁,由于A处于阻塞状态所以它不参与锁的竞争,那么线程C此时竞争到了对象O的锁并开始执行;

在线程C执行的过程中调用了对象O的notify()方法,此时线程调度器会随机的去唤醒线程A或者线程B,注意,不是全部都唤醒,而是只唤醒一个,那么被唤醒的那个线程从阻塞状态恢复到就绪状态,也就是这个被唤醒的线程接下来可以参与对象O锁的竞争了,另外没有被唤醒的线程依旧处于阻塞状态;

假如线程C调用的并不是notify()方法而是notifyAll()方法,那么线程调度器会唤醒所有在对象O等待队列的线程,也就是将线程A和线程B都唤醒,这个时候线程A和线程B都从阻塞状态恢复到就绪状态,也就是可以参与对象O锁的竞争当中了;

那么线程C在执行的过程当中,先执行对象O的notifyAll()方法,再执行对象O的wait()方法,这个时候线程C就进入了对象O的等待队列处于阻塞状态,被唤醒的线程A和线程B开始竞争对象O的锁,获取到锁的那个线程,会从之前调用wait()方法的地方继续执行,直到下一次释放对象O的锁或者线程执行完毕。

总结:调用wait()方法会释放对象的监视器锁,让当前线程进入对象的等待队列,处于阻塞状态,并释放cpu的执行权,直到其他线程调用该对象的notify()方法【可能被唤醒】或者notifyAll()方法【没有意外,一定被唤醒】才恢复就绪状态,可以参与对象锁的竞争。

下面是通过代码验证:

public class WaitTest {

    private Object object = new Object();

    public void threads() throws InterruptedException {

        Thread thread1 = new Thread(() -> {
            synchronized (object){
                try {
                    System.out.println("线程1   获取对象锁");
                    System.out.println("线程1   阻塞,释放锁");
                    object.wait();
                    System.out.println("线程1   被唤醒,执行完毕");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized(object){
                try {
                    System.out.println("线程2   获取对象锁");
                    System.out.println("线程2   阻塞,释放锁");
                    object.wait();
                    System.out.println("线程2   被唤醒,执行完毕");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });

        Thread thread3 = new Thread(() -> {
            synchronized(object){
                System.out.println("线程3   获取对象锁");
                System.out.println("线程3   调用notify");
                object.notify();
                System.out.println("线程3   执行完毕,释放锁");
            }

        });

        thread1.start();
        thread2.start();
        //让线程3休眠两秒再开始执行,保证线程1和2先进入object的等待队列
        Thread.sleep(2000);
        thread3.start();

    }

    public static void main(String[] args) throws InterruptedException {
        WaitTest waitTest = new WaitTest();
        waitTest.threads();
    }


}

创建一个Object对象,,threads()方法内创建了三个线程
线程1和2调用wait()方法阻塞自己 线程3用来唤醒

第一种情况:
线程1和线程2调用wait() 线程3调用notify()
执行结果:在这里插入图片描述
在这里插入图片描述
执行多次后的结果,,在线程3执行完毕后要么线程1执行结束要么线程2执行结束然后主线程就结束了,说明在线程3调用notify()方法后只唤醒了线程1、2中的其中一个去执行,另外一个依旧在阻塞状态中,没有参与锁的竞争。

第二种情况:
线程1和线程2调用wait() 线程3调用notifyAll()
在这里插入图片描述
执行结果:
在这里插入图片描述
在这里插入图片描述在线程3调用notifyAll后,处于阻塞的线程1和2都被唤醒,并且执行了,不过执行的顺序是不固定的,,这是因为线程需要竞争到对象锁,所以在调用notifyAll后具体是哪个阻塞线程继续执行,这个是不确定的;

第三种情况:
线程1,2调用wait(long time),线程3调用notify()

线程1中的wait()现在改成wait(long time)方法
在这里插入图片描述
让线程1等待一秒,看看执行结果:
在这里插入图片描述
线程1在wait(1000)后释放了锁,并且线程2获取到了并调用了wait方法进入了对象的等待队列,在线程3还没有获取到对象锁前,线程1就被唤醒了
说明,wait(long time)和wait方法一样,在被调用后,线程会释放对象的锁让其他线程去竞争,然后在定义的time到了之后自动被唤醒从阻塞状态变为就绪状态。

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值