【Java多线程】生命周期,线程状态,状态流转

线程状态

  1. 新建:线程新建
  2. 就绪:已经触发start(),还未抢占到CPU资源
  3. 运行:线程运行中
  4. 等待:无限制等待,被唤醒才能进入就绪状态
  5. 超时等待:有时间的等待,等待时间已过,就如就绪状态
  6. 阻塞:线程阻塞,需要获取到锁才能进入就绪状态
  7. 终止:现在执行完毕或者手动关闭

线程状态流转图

在这里插入图片描述

新建->就绪

线程调用 thread.start() 就如就绪状态

就绪->运行

就绪线程抢占到CPU时间片会进入到运行状态

运行->就绪

  • 系统
    运行中的线程不一定一直都会是运行状态,没有获得时间片又会回到就绪状态。
    参考:线程的调度与时间片

  • yield()
    作用:放弃当前的CPU资源,让其他任务去抢占CUP资源(只会给相同优先级或者更高优先级的现场运行的机会)

运行->等待、就绪->等待

  • Object.wait()
  • Object.join()
  • JUC Lock Condition 中的await()
  • LockSupport.park()

唤醒机制具体详解参考:https://blog.csdn.net/weixin_42480780/article/details/115904832

等待->就绪

  • Object.notify()、Object.notifyAll()
  • JUC Lock Condition 中的 signal()
  • LockSupport.unpark

运行->超时等待、就绪->超时等待

  • Object.sleep(long)
  • Object.wait(long)
  • Object.join(long)
  • LockSupport.parkNanos(long)
  • LockSupport.parkUntil(long)

超时等待->就绪

  • 超时等待时间已过
  • Object.notify()、Object.notifyAll()
  • JUC Lock Condition 中的 signal()
  • LockSupport.unpark

运行->阻塞、就绪->阻塞

  • 抢占锁资源

运行->终止、就绪->终止

非介入终止

  • 线程执行完成

介入终止线程的方法

  • Thread.stop():线程不安全,不推荐
  • 设置中断标识为thread.interrpt()

线程的调度与时间片

	由于CPU的计算频率非常高,每秒计算数十亿次,
因此可以将CPU的时间从毫秒的维度进行分段,
每一小段叫作一个CPU时间片。

目前操作系统中主流的线程调度方式是:基于CPU时间片方式进行线程调度

	线程只有得到CPU时间片才能执行指令,处于执行状态,
	没有得到时间片的线程处于就绪状态,等待系统分配下一个CPU时间片。
	由于时间片非常短,在各个线程之间快速地切换,
	因此表现出来的特征是很多个线程在“同时执行”或者“并发执行”。

线程的调度模型目前主要分为两种:分时调度模型和抢占式调度模型。

  1. 分时调度模型:系统平均分配CPU的时间片,所有线程轮流占用CPU,即在时间片调度的分配上所有线程“人人平等”。

  2. 抢占式调度模型:系统按照线程优先级分配CPU时间片。优先级高的线程优先分配CPU时间片,如果所有就绪线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些。

     由于目前大部分操作系统都是使用`抢占式调度模型`进行线程调度,
     Java的线程管理和调度是委托给操作系统完成的,与之相对应,
     Java的线程调度也是使用抢占式调度模型,因此Java的线程都有优先级。
    

线程等待方法

Thread类
thread.join()

	作用:当前线程等待调用join()方法的线程执行完再执行
	底层原理:利用wait()方法实现

thread.sleep(long)

	作用:让当前线程休眠一段时间
	特点:任何地方都能使用,需要捕获InterruptedException异常

thread.yield()

	作用:线程让出CPU时间片

Object类
wait()

作用:线程等待
特点:必须配合synchronized使用,唤醒必须配合Object中的notify()、notifyAll()方法

JUC-LOCK-Condition类
await()

作用:线程等待
特点:必须配合lock使用,唤醒必须配合JUC-LOCK-Condition中的signal()、signalAll()方法

LockSupport类
park()

作用:线程等待
特点:底层利用Unsafe类实现

线程等待方法的区别

thread.sleep(long) 与 object.wait() 与 object.wait(long) 的区别

  1. 使用限制

    sleep(long)在线程的任何地方都能使用、
    wait() 、wait(long) 需要配合synchronized使用
    wait() 唤醒需要配合notify() 或者 notifyAll() 使用
    
  2. 不同的类

    sleep(long) 在 Thread类中,wait()、wait(long)在Object类中
    
    为什么这样设计?
    
    因为sleep(long)是让当前线程休眠,
    不涉及到对象类,也不需要获取对象的锁,
    所以是线程类方法。wait()是让获得对象锁的线程实现等待,
    前提是获取到对象的锁,所以是类的方法。
    
  3. 使用场景

    sleep() 一般用户当前线程休眠,wait() 用于多线程之间的通信

  4. 释放锁

    wait()会释放获取到的锁并允许其他线程获取锁并继续执行,而sleep() 不会

  5. 线程切换(CPU资源)

    sleep()会让出CUP时间片,强制上下文切换
    wait()会让出CPU时间片,但是不会强制上下文切换

thread.sleep(long) 与 thread.yield()的区别

相同点:
1. 暂停当前线程
2. 如果获取到锁资源,都不会释放锁
3. 都会让出CPU时间片资源

不同点:
1. sleep() 可以指定休眠时间,而yield则依赖CPU的时间片划分
2. yield不能被中断,而sleep则可以被中断(需要捕获中断异常)
3. sleep() 让出CPU时间片给其他线程运行的机会不会考虑优先级,而yield() 只会给相同优先级或者更高优先级的线程运行的机会。
4. sleep()方法声明抛出InterruptedException异常,yield没有

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值