欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java学习日志(十二): 线程状态,等待与唤醒案例

程序员文章站 2022-05-04 17:53:24
...

JavaEE学习日志持续更新----> 必看!JavaEE学习路线(文章总汇)

线程状态

在API中 java.lang.Thread.State 这个枚举中给出了六种线程状态:

线程状态 导致状态发生条件
NEW(新建) 线程刚被创建,但是并未启动。还没调用start方法。
Runnable(可运行) 线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。
Blocked(锁阻塞) 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
Waiting(无限等待) 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
Timed Waiting(计时等待) 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、 Object.wait。
Teminated(被 终止) 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

Java学习日志(十二): 线程状态,等待与唤醒案例

等待与唤醒案例(包子铺案例)

等待与唤醒:线程之间的通信
Object类中的方法

  • void wait() 导致当前线程等待它被唤醒,通常是通知或中断 。
  • void notify() 唤醒正在此对象监视器(对象锁)上等待的单个线程。

注意:

  1. wait和notify方法必须由锁对象调用(必须是同个锁对象
    锁对象–>wait() 锁对象–>notify()
  2. wait和notify方法一般写在同步中

案例:包子铺案例

需求
两大线程:设线程A(包子铺),执行生产包子的动作。线程B(吃货),执行吃包子的操作

共享资源:包子

执行动作:生产一个包子,吃一个包子

分析
包子的状态进行分析
没有包子:吃货线程唤醒包子铺线程—>吃货线程等待—>包子铺线程做包子—>包子铺做好包子—>修改包子的状态—>有包子
有包子:包子铺唤醒吃货线程—>包子铺线程等待—>吃货吃包子—>修改包子的状态—>没有包子
…(循环)

代码实现:

资源类:包子,其中有皮,陷,包子的状态

public class BaoZi {
    String pi;
    String xian;
    //包子状态,初始值为false,没有包子
    boolean flag = false;
}

包子铺类:是一个线程类,线程任务:生产包子

对包子的状态进行判断:
true:有包子
        包子铺线程调用wait等待
false:没有包子
        包子铺线程生产包子
        生产x皮x陷的包子
        生产包子花费3秒
        生产完包子,修改包子状态为true
        包子铺线程唤醒吃货线程,吃包子

注意:

  1. 生产包子和吃包子,只能有一个在执行,需要使用同步技术
  2. 同步技术需要使用锁对象,可以使用包子对象
    在成员位置创建一个包子对象
    使用构造方法为包子变量赋值
public class BaoZiPu implements Runnable {
    //在成员位置创建一个包子对象
    BaoZi bz;
    //使用构造方法为包子变量赋值
    public BaoZiPu(BaoZi bz) {
        this.bz = bz;
    }

    //线程任务:生产包子
    @Override
    public void run() {
        while(true){
/*
            1.生产包子和吃包子,只能有一个在执行,需要使用同步技术
            2.同步技术需要使用锁对象,可以使用包子对象
         */
            synchronized (bz){
                //对包子状态进行判断
                if(bz.flag==true){
                    //true:有包子
                    //            包子铺线程调用wait等待
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //包子铺被吃货唤醒之后执行的代码
                //false:没有包子,包子铺线程生产包子
                //生产x皮x陷的包子
                bz.pi = "薄皮";
                bz.xian = "玉米鲜肉";
                System.out.println("包子铺正在生产"+bz.pi+bz.xian+"的包子!");
                //生产包子花费3秒
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //生产完包子,修改包子状态为true
                bz.flag = true;
                //包子铺线程唤醒吃货线程,吃包子
                bz.notify();
                System.out.println("包子铺已经生产好"+bz.pi+bz.xian+"的包子!");
            }
        }
    }
}

吃货类:是一个线程类,线程任务:吃包子

对包子的状态进行判断:
false:没有包子
    吃货线程调用wait等待
true:有包子
    吃货线程开始吃包子
    打印吃x皮x陷的包子
    吃完包子,修改包子的状态为false
    吃货线程唤醒包子铺线程,做包子

注意:

  1. 生产包子和吃包子,只能有一个在执行,需要使用同步技术
  2. 同步技术需要使用锁对象,可以使用包子对象
    在成员位置创建一个包子对象
    使用构造方法为包子变量赋值
public class ChiHuo implements Runnable{
    //在成员位置创建一个包子对象
    BaoZi bz;
    //使用构造方法为包子变量赋值
    public ChiHuo(BaoZi bz) {
        this.bz = bz;
    }

    //线程任务:吃包子
    @Override
    public void run() {
        while (true){
            /*
            1.生产包子和吃包子,只能有一个在执行,需要使用同步技术
            2.同步技术需要使用锁对象,可以使用包子对象
         */
            synchronized (bz){
                //对包子的状态进行判断
                //        false:没有包子
                if (bz.flag==false){
                    //吃货线程调用wait等待
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            /*
                吃货线程被包子铺线程唤醒之后执行的代码
             */
                //true:有包子,吃货线程开始吃包子
                //打印吃x皮x陷的包子
                System.out.println("吃货正在吃"+bz.pi+bz.xian+"的包子!");
                //吃完包子,修改包子的状态为false
                bz.flag = false;
                //吃货线程唤醒包子铺线程,做包子
                bz.notify();
                System.out.println("吃货已经吃完了"+bz.pi+bz.xian+"的包子!包子铺赶紧生产包子!");
                System.out.println("-----------------------");
            }
        }
    }
}

测试类
创建一个包子对象
创建一个包子铺线程,生产包子
创建一个吃货线程,吃包子

public class Demo01 {
    public static void main(String[] args) {
        //创建一个包子对象
        BaoZi bz = new BaoZi();
        //创建一个包子铺线程,生产包子
        new Thread(new BaoZiPu(bz)).start();
        //创建一个吃货线程,吃包子
        new Thread(new ChiHuo(bz)).start();
    }
}

运行结果:

包子铺正在生产薄皮玉米鲜肉的包子!
包子铺已经生产好薄皮玉米鲜肉的包子!
吃货正在吃薄皮玉米鲜肉的包子!
吃货已经吃完了薄皮玉米鲜肉的包子!包子铺赶紧生产包子!
-----------------------
包子铺正在生产薄皮玉米鲜肉的包子!
包子铺已经生产好薄皮玉米鲜肉的包子!
吃货正在吃薄皮玉米鲜肉的包子!
吃货已经吃完了薄皮玉米鲜肉的包子!包子铺赶紧生产包子!
-----------------------
...