java线程的6种状态、等待唤醒机制 wait()、notify()

目录

一 线程的6种状态

二 无限等待wait()、唤醒notify()案例详解

2.1 案例介绍

2.2 代码

三 wait(long)和sleep(long)

 四 线程之间的通信(等待唤醒机制)

无限等待wait()、唤醒notify()案例升级


一 线程的6种状态

1 新建状态:new Thread(),new Thread子类() → 尚未启动的线程
    调用start()方法之后,就开启了线程,这时线程分为 运行状态 和 阻塞状态.
    
2 运行状态:线程抢到了CPU执行权的
3 阻塞状态:线程没抢到CPU执行权的
    运行状态 和 阻塞状态 可以相互转换
    运行状态 和 阻塞状态 都有cpu的执行资格

4 死亡状态:run()方法执行结束,或者调用了stop(),或者发生了异常,线程就死亡了.
    stop()方法:强制停止一个正在运行的线程,无论此时线程是何种状态

5 睡眠(休眠)状态:线程调用了sleep(long)或wait(long)方法 → 休眠状态过时间了,可以自己醒过来
6 无限等待状态(植物人状态):线程调用了wait()方法并且没有传参数 → 自己醒不过来,只能调用notify()方法来唤醒无限等待状态
    无限等待状态 和 睡眠状态 称为  冻结状态.


 

二 无限等待wait()、唤醒notify()案例详解

2.1 案例介绍

顾客去买包子,包子可能没有要现做,
但是不知道要多久才能做好,因为不知道顾客要等待的时间,所以调用了wait()方法,此时顾客属于无限等待状态
包子做好了,老板通知顾客包子好了,notify()一下

wait()方法和notify()方法都是object类的方法
notify()之后,会继续执行wait()方法之后的代码

notify()是随机唤醒一个线程,notifyAll()唤醒所有线程

注意:
老板和顾客线程要用同步代码块包裹,保证只能实行其中的一个
锁对象必须是唯一的
只有锁对象才能调用wait()方法和notify()方法

2.2 代码

package threadState;

public class WaitAndNotify {
    public static void main(String[] args) {
        //锁对象必须是唯一的
        final Object obj = new Object();
        //创建一个顾客线程
        new Thread(){
            @Override
            public void run() {
                while (true){

                    //老板和顾客线程要用同步代码块包裹,保证只能实行其中的一个
                    synchronized (obj){
                        System.out.println("顾客说要1个素馅的1个肉馅的包子");
                        //无限等待
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //唤醒之后的代码
                        System.out.println("包子已经做好了,开吃");
                        System.out.println("______________________________");

                    }
                }
            }
        }.start();
        //创建一个老板线程
        new Thread(){
            @Override
            public void run() {
                while(true){
                    //花了3S做包子
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //老板和顾客线程要用同步代码块包裹,保证只能实行其中的一个
                    synchronized (obj){
                        System.out.println("老板花3S做好了包子");
                        obj.notify();
                    }

                }
            }
        }.start();
    }
}

 此处用的匿名内部类实现线程

运行效果

三 wait(long)和sleep(long)

都是设置倒计时结束后,线程就会自动醒来,线程醒来后变成运行或阻塞状态
sleep(long)是Thread的方法
wait(long)是object方法,wait(long)设置睡眠时间,也可以用notify()或者notifyAll()提前唤醒线程

 

 四 线程之间的通信(等待唤醒机制)

为什么要处理线程之间的通信?
    因为多线程并发执行时,默认情况下CPU是随机切换线程的,当我们需要多个线程共同完成一件任务时,
    并且希望他们有规律的执行,那么多线程之间需要一些通信,来帮助我们完成多线程共同操作同一份数据.

如何保证线程之间可以有效利用资源?
    等待唤醒机制 (避免多个线程对同一共享资源的争夺)

无限等待wait()、唤醒notify()案例升级

等待唤醒机制
重点:有效利用资源 (生产一个包子,吃一个包子)


流程:
    包子是共享资源,不能一边生产一个包子一边吃这个包子,作为锁对象
    1 有包子的时候(flag==true):
        包子铺等着wait() → 吃货吃包子 → 包子吃完了 flag==false → 通知包子铺 notify() → 吃货等着wait() ,
    2 没有包子的时候(flag==false):
        吃货等着wait() → 包子铺生产包子 → 包子生产好了 flag==true → 通知吃货 notify() → 包子铺等着wait()
    

代码

包子类

package threadWaitAndNotify;

public class Baozi {
    String kind; //包子种类
    Boolean flag =  false; //false 没有包子,true 有包子

}

 包子铺类

package threadWaitAndNotify;

import androidx.annotation.Nullable;

public class BaoziShop extends Thread{
    //共享资源包子作为锁对象
    private Baozi baozi;

    public BaoziShop(Baozi baozi) {
        this.baozi = baozi;
    }

    @Override
    public void run() {
        int count = 0;
        while (true) {
            synchronized (baozi){
                if(baozi.flag){
                    //1 有包子的时候
                    //包子铺不用做包子
                    try {
                        baozi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
                //2 没有包子的时候会被唤醒,走wait()之后的代码
                //被唤醒之后,包子铺生产包子
                //增加趣味性,生产两种包子
                if(count%2==0){
                    //如果是count是偶数
                    baozi.kind = "素馅包子";
                }else{
                    //如果是奇数
                    baozi.kind = "鲜肉大包";
                }
                count++;
                System.out.println("包子铺正在生产"+baozi.kind);
                //生产包子需要3秒钟
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //生产好包子之后,修改状态为有
                baozi.flag =true;
                //通知吃货吃包子
                baozi.notify();
            }
        }
    }
}

 吃货类

package threadWaitAndNotify;

import androidx.annotation.Nullable;

public class Chihuo extends Thread{
    //共享资源包子作为锁对象
    private Baozi baozi;

    public Chihuo( Baozi baozi) {
        this.baozi = baozi;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (baozi){
                if(!baozi.flag){
                    //如果没有包子就等待
                    try {
                        baozi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //有包子的时候
                //被唤醒之后,有包子了,吃货可以吃包子了
                System.out.println("吃货正在吃"+baozi.kind+"的包子");
                System.out.println("吃货吃完了"+baozi.kind+"包子");
                //吃完包子,包子没有了
                baozi.flag= false;
                //通知包子铺生产包子
                baozi.notify();
                System.out.println("------------------------------");
            }
        }
    }
}

 测试类

package threadWaitAndNotify;

public class Ceshi {
    public static void main(String[] args) {
        Baozi baozi = new Baozi();
        new BaoziShop(baozi).start();;
        new Chihuo(baozi).start();
    }
}

效果:


注意:
1 wait()与notify()方法必须由同一个锁对象调用
2 wait()与notify()方法属于object类
3 wait()与notify()方法必须在同步代码块或同步方法中使用,因为必须由锁对象来调用这两个方法

关于线程的安全问题及解决方案请点这里

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值