多线程中的等待唤醒机制wait()、notify()、sleep()方法详解(含底层工作原理及代码实现)

1.线程的工作状态

(图源:网课视频)

注意:(1)在使用了同步方法的线程中,获得锁对象的线程处于运行状态(RUNABLE),而其余争夺锁对象的线程处于阻塞状态。一旦拥有锁对象的线程释放了该锁,那么它就会重新进入线程池和其他线程一块争夺锁对象,而获得锁对象的线程将由阻塞状态(BLOCKED)进入运行状态。

(2)计时等待:线程对象调用Object.wait()、Thread.sleep()方法会使自身进入睡眠状态从而退出运行的状态,内部参数为用户想要等待的毫秒值(ms)

(3)等待:线程对象调用Object.wait()方法

(4)唤醒:运行中的线程调用Object.notify()方法,会唤醒等待中的线程,但是被唤醒的线程不会马上进入运行状态,而是与其他阻塞状态的线程一块抢夺cpu的执行权。

2.案例分析

(1)sleep()方法:

题目描述:

扫描二维码关注公众号,回复: 14655011 查看本文章

通过分析,我们发现兔子线程和乌龟线程之间没有共用的数据,那么这道多线程问题是不涉及线程安全问题的。所以,我们在兔子和乌龟线程各自的run()方法中使用sleep()方法即可,实现速度的控制和模拟耗时。

代码如下:

主方法

public class Main {
    public static void main(String[] args) {
        new Race.RabbitThread().start();
        new Race.TurtleThread().start();
        return;
    }
}

线程(Race类中实现两种线程):

public class Race {
    //兔子的速度0.2s/m-----每1s休息10s
    //乌龟的速度1s/m-----每5s休息1s
    static class RabbitThread extends Thread{
        @Override
        public void run() {
            int len = 0;
            while(len<20){
                try {
                    Thread.sleep(200);
                    System.out.println("兔子跑了"+(++len)+"米");
                    if(len%5==0){
                        Thread.sleep(5000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("兔子到达了终点!");
        }
    }
    static class TurtleThread extends Thread{
        @Override
        public void run() {
            int len = 0;
            while(len<20){
                try {
                    Thread.sleep(1000);
                    System.out.println("乌龟跑了"+(++len)+"米");
                    if(len%5==0){
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("乌龟到达了终点!");
        }
    }
}

执行结果:

(2)sleep()和nitify()方法:

public class Test01 {
    public static void main(String[] args) {
        //创建一个锁对象
        Object MAIN_LOCK = new Object();
        //新建一个顾客线程
        new Thread() {
            @Override
            public void run() {
                //线程同步技术
                synchronized (MAIN_LOCK) {
                    System.out.println("告诉老板需要购买汽水的种类和数量");
                    //动作执行完后,调用wait()方法,放弃cpu的执行权,等待老板制作汽水
                    try {
                        MAIN_LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //顾客获得汽水(线程被唤醒之后,执行该语句)
                    System.out.println("顾客获得汽水");
                }
            }
        }.start();
        //新建一个老板线程
        new Thread(){
            @Override
            public void run(){
                //老板花费3s时间制作汽水
                try{
                    Thread.sleep(3000);
                    System.out.println("老板花费3s时间制作汽水");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //同步技术,唤醒顾客线程(即提醒顾客可以喝汽水了)
                synchronized (MAIN_LOCK){
                    System.out.println("汽水制作完毕并且告知顾客");
                    MAIN_LOCK.notify();
                }
            }
        }.start();
    }
}

 执行结果:

备注:在执行汽水制作的过程,编译器有3s的等待

猜你喜欢

转载自blog.csdn.net/m0_56603583/article/details/124526862
今日推荐