• 线程的状态


    目录

    线程的五大状态

    线程的状态转换 

    线程状态转换图

    yield方法

    理解三大等待状态


    线程的五大状态

    • NEW(新建状态)  新创建了一个线程对象,但是还没有调用start()方法
    • RUNNABLE(运行态) Java线程中将就绪(READY)和运行中(RUNNING)两种状态并称为运行态,其一个线程被创建了,并且调用了这个线程对象的start()方法,这个线程对象就处于可运行的线程池中,等待被调度选中,获得CPU的使用权,这种状态称为就绪态(万事俱备,只差CPU),当这个线程获得了CPU的使用权,那么就会从就绪态变为运行中
    • 阻塞(BLOCKED)表示这个线程阻塞于锁
    • 等待(WAITING)进入这种状态的线程需要等待其他线程做出一些特定的动作(通知或者中断)
    • 超时等待(TIME_WAITING)该状态不同于WAITINGM,它是指定的时间后自行返回
    • 终止(TERMINATED) 表示该线程已经执行完毕

    线程的状态转换 

    线程状态转换图

     

    初始状态

    关于NEW,我们通过实现Runnable接口或者继承Thread可以得到一个线程类,new出一个线程对象出来,这个线程就处于NEW状态

     

    就绪状态(RUNNABLE之READY)

    1. 就绪(READY)和运行中(RUNNING)在就绪只是说明你有资格运行,只有系统调度你去运行你才是真正的RUNNING,否则你永远是READR
    2. 处于NEW态的线程调用start()就进入就绪状态
    3. 当一个线程sleep()方法结束,其他线程join结束,某个线程拿到了对象锁,这些线程也就进入了就绪状态
    4. 当前线程时间片用完,或者调用当前运行线程的yield()方法,当前线程进入就绪状态
    5. 锁池里的线程拿到对象锁之后,进行就绪状态

    运行中状态(RUNNABLE之RUNNING)

    • 线程的调度程序从可运行池中(RUNNING和READY)挑选一个线程作为运行线程,这是线程变为运行状态的唯一一种方式

    yield方法

    1. package thread;
    2. public class ThreadYield {
    3. public static void main(String[] args) {
    4. Thread t1 = new Thread(() -> {
    5. while (true) {
    6. System.out.println(Thread.currentThread().getName());
    7. // 帅哥线程就会让出CPU,进入就绪态,等待被CPU继续调度
    8. Thread.yield();
    9. }
    10. },"帅哥线程");
    11. t1.start();
    12. Thread t2 = new Thread(() -> {
    13. while (true) {
    14. System.out.println(Thread.currentThread().getName());
    15. }
    16. },"美女线程");
    17. t2.start();
    18. }
    19. }

     

    •  我们发现帅哥线程执行yield,让出CPU的使用权,帅哥线程只是让出CPU,但是下此调度什么线程,还是由我们的操作系统说的算,可能下次调用的还是帅哥线程(只不过是我们执行完输出这个语句,就把CPU让出去了),也有可能是美女线程,我们无法干涉,只是每次执行到帅哥线程,都会把CPU让出去,让美女线程执行的次数可能较多一点

    阻塞状态(BLOCKED)

    • 阻塞状态就是线程阻塞在进入synchronized关键字修饰的方法或者代码块

    等待(WAITING)

    • 处于这种状态的线程不会被分配CPU执行时间,它们要等待被显式地唤醒,否则会处于无限期等待的状态。

     超时等待(TIMED_WAITING)

    • 处于这种状态的线程不会被分配CPU执行时间,不过无须无限期等待被其他线程显示地唤醒,在达到一定时间后它们会自动唤醒。

    理解三大等待状态

    1. package thread;
    2. public class ThreadBlocked {
    3. public static void main(String[] args) {
    4. Object lock=new Object();
    5. Thread t1=new Thread(new Runnable() {
    6. @Override
    7. public void run() {
    8. synchronized (lock){
    9. while (true){
    10. try {
    11. //TIMED_WAITING
    12. //时间到了,自动结束等待,这里是等待1秒
    13. Thread.sleep(1000);
    14. } catch (InterruptedException e) {
    15. e.printStackTrace();
    16. }
    17. }
    18. }
    19. }
    20. },"t1");
    21. t1.start();
    22. Thread t2=new Thread(new Runnable() {
    23. @Override
    24. public void run() {
    25. //t2想执行这个里面的代码,必须等待t1释放lock这个锁
    26. //因为t1先获得这个资源,对其上锁
    27. synchronized (lock){
    28. System.out.println("呵呵 小垃圾");
    29. }
    30. }
    31. },"t2");
    32. t2.start();
    33. }
    34. }

     

    •  我们发现在t1在sleep后,处于TIMED_WAITING状态,意思就是t1等待一秒后在继续运行(这里的运行只是RUNNABLE),何时是真正的使用CPU由调度程序说的算
    • 我们发现t2处于BLOCKED状态,是因为t1先进入了synchronized,获得了lock这个资源,相当于对这个资源上锁了,如果t2想执行synchronized里的代码,就必须等待t1释放这个资源(解锁)

     

    1. package thread;
    2. public class ThreadBlocked {
    3. public static void main(String[] args) {
    4. Object lock=new Object();
    5. Thread t1=new Thread(new Runnable() {
    6. @Override
    7. public void run() {
    8. synchronized (lock){
    9. // while (true){
    10. // try {
    11. Thread.sleep(1000);
    12. // lock.wait();
    13. // } catch (InterruptedException e) {
    14. // e.printStackTrace();
    15. // }
    16. // }
    17. try {
    18. // Thread.sleep(1000);
    19. lock.wait();
    20. System.out.println("我被唤醒了");
    21. } catch (InterruptedException e) {
    22. e.printStackTrace();
    23. }
    24. }
    25. }
    26. },"t1");
    27. t1.start();
    28. Thread t2=new Thread(new Runnable() {
    29. @Override
    30. public void run() {
    31. synchronized (lock){
    32. System.out.println("呵呵 小垃圾");
    33. }
    34. }
    35. },"t2");
    36. t2.start();
    37. }
    38. }

     

    • 我们发现t2程序正常的运行结束,但是t1陷入死等了,状态是wait,如果想让t1结束wait状态,我们必须需要别的线程进行lock资源的notify(),这需要我们后面细讲其中的原理,wait必须搭配synchronized

    总结

    其实这三种其本质都是等待,只是等待的原因不一样

     

     终止状态(TERMINATED)

    • 当线程的run()方法完成时,或者主线程的main()方法完成时,或者抛出异常不正常执行完毕,我们就认为它终止了。这个线程对象也许是活的,但是它已经不是一个单独执行的线程。线程一旦终止了,就不能复生。
    • 在一个终止的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。
       

  • 相关阅读:
    Redis数据类型之Sorted Set的使用
    leetcode1669. 合并两个链表(java)
    面试大厂Java工程师后整理份300+页Java面试宝典
    深圳市第十二届职工技术创新运动会暨2022年深圳技能大赛—集成电路应用开发职业技能竞赛
    Ansible 批处理实战
    开发者体验:现代企业架构的关键一环
    企业云性能监控
    乐观锁思想在JAVA中的实现——CAS
    Cadence OrCAD Capture 层次化设计单模块多次复用功能说明与效果演示
    Python同步异步爬虫通过代理访问HTTPS
  • 原文地址:https://blog.csdn.net/qq_50985215/article/details/125464862