java多线程:线程状态与线程等待唤醒机制的理解

写在前面

2020年疫情以来,坚持在csdn博客写文章已经有两个多月了,刚开始动笔的原因,主要就是为了把一些知识点及工作中碰到的问题,通过博客的方式记录下来,但随着时间的加长,对于写博客也有了一些新的认识,今天借这个机会,把个人想法记录在案:

刚开始的想法
  • 刚开始写的时候担心自己坚持不下来
  • 动笔了感觉没什么写,内容不充实
  • 在互联网上写博客,总是要被人看的,怕被人笑话

  • 在内心忐忑之间,还是坐下来写了,反正写的都是技术文:从书上学到的,工作中碰到的,确有其事;文章中的样例代码,都是自己手把手写的且通过调试运行,贵在真实。
现在的心境

不以成为职业作家为目标的话,写文章其实没那么难。某种程度上,它就跟我们平时说话、唱歌一样,只是一种沟通交流的手段,源自我们与生俱来的表达欲望。

慢慢地,写博客成了近几个月的习惯,几天不码字感觉少了点什么:

  • 把技术通过文字的形式写下来更容易理清逻辑,加深认知;
  • 把知识点通过系列文章分段的方式写下来,是对思维的刻意训练;
  • 坚持写博客,整理技术素材,能做到温故而知新;
  • 通过互联网的传播,通过网友的点评,更加能鞭策作者。

废话到此为止,接下来进入正题。

线程状态概述

java线程在运行的生命周期有6种不同的状态,在给定的一个时刻,线程只能处于其中的一个状态。

状态 说明
NEW 新建状态又称为初始状态,线程刚被创建,但没调用start()开始运行
RUNNABLE 运行状态,java线程将操作系统中就绪和运行状态统称为”运行中“状态
BLOCKED 阻塞状态,线程被”锁“阻塞时的状态
WAITING 等待状态又称为永久等待状态,处于永久等待状态的线程需要被其他线程唤醒或中断
TIMED_WAITING 休眠等待状态又称为计时等待状态,处于计时等待状态的线程休眠结束后自行唤醒
TERMINATED 终止状态,线程运行结束

在这里插入图片描述

线程的等待与唤醒

  • 创建一个全局的锁对象objectLock;
  • 创建一个线程全局的运行标志flag;
  • 运行线程0,并通过objectLock进行无限等待状态;
  • 运行线程1,并通过objectLock唤醒该锁对象上的等待线程,并将运行标志flag置为结束;
  • 线程0得到唤醒通知后,继续运行,并根据结束标志的状态结束运行。
/**
 * 线程状态--线程等待唤醒状态的相互转换
 *
 * @author zhuhuix
 * @date 2020-05-10
 */
public class ThreadStatus {

    //创建静态锁对象
    static final Object objectLock = new Object();
    //线程结束标志
    static boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        //调用等待线程执行
        new Thread(new Waiting()).start();
        TimeUnit.SECONDS.sleep(1);
        //调用唤醒线程执行
        new Thread(new Notify()).start();
    }

    /**
     * 等待线程
     */
    static class Waiting implements Runnable {
        @Override
        public void run() {
            synchronized (objectLock) {
                while (flag) {
                    try {
                        System.out.println(Thread.currentThread().getName() + "线程正在等待:"
                                + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now()));
                        objectLock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "线程完成运行:"
                        + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now()));
            }
        }
    }

    /**
     * 唤醒线程
     */
    static class Notify implements Runnable {
        @Override
        public void run() {
            synchronized (objectLock) {
                System.out.println(Thread.currentThread().getName() + "线程唤醒:"
                        + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now()));
                objectLock.notify();
                flag = false;
            }
        }
    }

}

输出结果:
在这里插入图片描述

线程的计时等待

  • 线程在休眠时加上计时,无需再被被其他唤醒,计时时间到了,自行醒来。
/**
 * 线程状态--线程的计时等待
 *
 * @author zhuhuix
 * @date 2020-05-10
 */
public class ThreadWaitAndNotify {
    //创建静态锁对象
    static final Object objectLock = new Object();

    public static void main(String[] args) {
        //调用等待线程执行
        new Thread(new ThreadWaitAndNotify.Waiting()).start();
    }

    /**
     * 等待线程
     */
    static class Waiting implements Runnable {
        @Override
        public void run() {
            synchronized (objectLock) {

                    try {
                        System.out.println(Thread.currentThread().getName() + "线程正在等待:"
                                + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now()));
                        objectLock.wait(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "线程完成运行:"
                        + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now()));

        }
    }

}


在这里插入图片描述

线程等待/唤醒机制的简单总结

等待方:

 synchronized (对象) {
	 while (条件不满足) {
       等待
     }
     运行业务逻辑 
 }

通知方:

 synchronized (对象) {
	   改变条件
       唤醒
 }

等待/唤醒机制的应用–生产者与消费者

  1. 生产者生产披萨,每生产满10个,通知消费者购买。
  2. 消费者购买披萨,若无披萨则等待生产者通知。
/**
 * 线程等待唤醒状态的应用--生产者与消费者问题
 *
 * @author zhuhuix
 * @date 2020-05-10
 */
public class ProduceConsumeThread {

    //创建静态锁对象
    static final Object objectLock = new Object();
    //披萨数量
    static int pizza = 0;

    public static void main(String[] args) {
        //生产者生产披萨
        new Thread(new ProduceConsumeThread.Produce()).start();
        //消费者购买披萨
        new Thread(new ProduceConsumeThread.Consume()).start();
    }

    /**
     * 生产者
     */
    static class Produce implements Runnable {
        @Override
        public void run() {
            while (true) {
                synchronized (objectLock) {
                    if (pizza >= 10) {
                        //通知消费者购买
                        objectLock.notifyAll();
                    } else {
                        pizza++;
                        System.out.println(Thread.currentThread().getName() + "生产出披萨:" + pizza + "个,"
                                + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now()));
                        try {
                            TimeUnit.SECONDS.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    /**
     * 消费者
     */
    static class Consume implements Runnable {
        @Override
        public void run() {
            while (true) {
                synchronized (objectLock) {
                    if (pizza == 0) {
                        try {
                            System.out.println(Thread.currentThread().getName() + "消费者正在等待购买:"
                                    + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now()));
                            objectLock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        pizza--;
                        System.out.println(Thread.currentThread().getName() + "消费者购买披萨," + "披萨还剩" + pizza + "个,"
                                + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now()));
                    }
                }
            }
        }
    }

}

运行结果如下:
在这里插入图片描述

原创文章 56 获赞 8 访问量 4716

猜你喜欢

转载自blog.csdn.net/jpgzhu/article/details/106036424