前言:线程的五种状态

本文是线程篇的一个分支,主要结合我的理解,看一下sleep和wait以及线程的一些状态
网上的图看起来都有点丑,我自己画了一幅:

1.New:       新建态:  new Thread ~ thread.start期间
2.Runnable:  可执行态: 可被CPU调度执行期间。
3.Running     运行态: 线程获取CPU权限进行执行
4.Blocked     阻塞状态: 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。|---等待阻塞:通过调用线程的wait()方法,让线程等待某工作的完成。|---同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用)时|---其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时
5.Dead        死亡状态: 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
复制代码

一、Thread.sleep简述

暂停当前线程,进入Blocked状态,把cpu片段让出给其他线程。

1.测试代码:
public class Main0 {static SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");public static void main(String[] args) {new Thread(new Car()).start();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}new Thread(new Ambulance()).start();}private static class Car implements Runnable {@Overridepublic void run() {System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车开始启动,在路上跑");System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车跑到终点");}}private static class Ambulance implements Runnable {@Overridepublic void run() {System.out.println(sdf.format(System.currentTimeMillis()) + ":救护车开始启动,在路上跑");System.out.println(sdf.format(System.currentTimeMillis()) + ":救护车跑到终点");}}
}
复制代码

2. 结果分析:注02:29代表当前时刻的分秒,即2分29秒
---->[运行结果]----------------------
02:29:小汽车开始启动,在路上跑
02:29:小汽车跑到终点
02:31:救护车开始启动,在路上跑
02:31:救护车跑到终点
复制代码

二、线程内sleep以及synchronized

1.子线程加入休眠
private static class Car implements Runnable {@Overridepublic void run() {System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车开始启动,在路上跑");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车跑到终点");}
}
复制代码

2.结果分析

Car线程的任务是睡5s,可见主线程的休眠没有影响到Car子线程的运行(休眠)

18:48:小汽车开始启动,在路上跑
18:50:救护车开始启动,在路上跑
18:50:救护车跑到终点
18:53:小汽车跑到终点
复制代码

3.当加锁睡眠时

在线程1中加synchronized(这里锁用sdf对象,你也可以任意)

public class Main2 {static SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");public static void main(String[] args) {new Thread(new Car()).start();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}new Thread(new Ambulance()).start();}private static class Car implements Runnable {@Overridepublic void run() {synchronized (sdf){System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车开始启动,在路上跑");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车跑到终点");}}}private static class Ambulance implements Runnable {@Overridepublic void run() {synchronized (sdf){System.out.println(sdf.format(System.currentTimeMillis()) + ":救护车开始启动,在路上跑");System.out.println(sdf.format(System.currentTimeMillis()) + ":救护车跑到终点");}}}
}
复制代码

2.结果分析

Car线程和Ambulance线程在运行时使用同一把锁,线程在休眠时不会释放锁
所以Ambulance线程需要等待Car线程执行完成,才能进行执行

23:46:小汽车开始启动,在路上跑
23:51:小汽车跑到终点
23:51:救护车开始启动,在路上跑
23:51:救护车跑到终点
复制代码

三、Object#wait()方法的作用

线程t1调用A对象wait()方法,会释放t1持有的锁,让t1进入等待队列(Blocked状态)
直到其他线程调用A对象的notify()方法notifyAll()方法t1进入同步队列(Blocked状态)
当t1获得锁后会进入就绪状态Runnable,获取CPU的调度权后会继续执行,再贴一遍这个图:


1.wait方法的使用

既然是释放当前线程的锁,那么不须有锁才行,而且必须用该锁的对象调用wait方法
比如上面是用sdf对象加锁的,必须使用sdf.wait();,否则会抛出InterruptedException

private static class Car implements Runnable {@Overridepublic void run() {synchronized (sdf) {System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车开始启动,在路上跑");try {Thread.sleep(3000);//模拟执行3s的任务之后} catch (InterruptedException e) {e.printStackTrace();}try {System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车紧急刹车....");sdf.wait();System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车开始启动....");} catch (InterruptedException e) {e.printStackTrace();}try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车跑到终点");}}
}
private static class Ambulance implements Runnable {@Overridepublic void run() {synchronized (sdf) {System.out.println(sdf.format(System.currentTimeMillis()) + ":救护车开始启动,在路上跑");System.out.println(sdf.format(System.currentTimeMillis()) + ":救护车跑到终点");}}
}
复制代码

2.结果分析

在Car线程调用sdf.wait();后,锁将被释放,然后Ambulance线程就可以持有锁运行了
如果不唤醒线程,线程将一直阻塞,就是根本停不下来。打个比方就是sdf是司机
wait()之后就把车钥匙扔了,然后熄火了。钥匙拿不回来,车就跑不了。需要notify()获取车钥匙

30:48:小汽车开始启动,在路上跑
30:51:小汽车紧急刹车....
30:51:救护车开始启动,在路上跑
30:51:救护车跑到终点
然后就阻塞在这里停不下来了....
复制代码

3.唤醒等待线程

注意wait和notify需要使用同一个对象,否则然并卵
在Ambulance线程跑完后唤醒Car线程,然后Car获取所后会进入就绪态

private static class Ambulance implements Runnable {@Overridepublic void run() {synchronized (sdf) {System.out.println(sdf.format(System.currentTimeMillis()) + ":救护车开始启动,在路上跑");System.out.println(sdf.format(System.currentTimeMillis()) + ":救护车跑到终点");sdf.notify();}}
}
复制代码

4.结果分析
40:23:小汽车开始启动,在路上跑
40:26:小汽车紧急刹车....
40:26:救护车开始启动,在路上跑
40:26:救护车跑到终点
40:26:救护车:喂,哥们,醒醒,你可以开了...
40:26:小汽车开始启动....
40:31:小汽车跑到终点
复制代码

四、Thread#join()方法 和Thread#yield

1.普通代码
public class Main6 {static SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");public static void main(String[] args) {Thread car = new Thread(new Car());car.start();System.out.println(sdf.format(System.currentTimeMillis()) + ":main线程结束");}private static class Car implements Runnable {@Overridepublic void run() {System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车开始启动,在路上跑");try {Thread.sleep(3000);//模拟执行3s的任务之后} catch (InterruptedException e) {e.printStackTrace();}System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车跑到终点");}}
}
复制代码

2.结果分析
26:28:小汽车开始启动,在路上跑
26:28:main线程结束
26:31:小汽车跑到终点
复制代码

3.join方法的使用

阻塞当前线程,知道join的线程结束或超时

public class Main6 {static SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");public static void main(String[] args) {Thread car = new Thread(new Car());car.start();try {car.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(sdf.format(System.currentTimeMillis()) + ":main线程结束");}private static class Car implements Runnable {@Overridepublic void run() {System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车开始启动,在路上跑");try {Thread.sleep(3000);//模拟执行3s的任务之后} catch (InterruptedException e) {e.printStackTrace();}System.out.println(sdf.format(System.currentTimeMillis()) + ":小汽车跑到终点");}}
}
---->[打印结果]-----------------------------
31:53:小汽车开始启动,在路上跑
31:56:小汽车跑到终点
31:56:main线程结束
复制代码

4.yield方法测试

让出线程的cpu调度权,之后再一起抢夺。运行状态-->就绪状态

public class Main7 {public static void main(String[] args) {Thread car = new Car("car");Thread ambulance = new Car("Ambulance");car.start();ambulance.start();}private static class Car extends Thread {public Car(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(getName() + "----" + i);if (i == 5) {yield();}}}}
}
复制代码

运行了几组数据,大部分满足让出调度权后,另一个线程执行,也有少量情况不是。
所以yield说明我现在不急,可以划划水,执行权可以让出去。不过接下来谁执行还是不定的。


五、小结

1.需要补充的点:

1.关于synchronized锁这里不展开,不了解的可以见:线程篇3:[-synchronized-]
2.关于synchronized锁对象需要一致,否则锁不住,然并卵。常用class对象,如Car.class
3.可以设置超时唤醒xxx.wait(3000),即3s后唤醒线程。
4.可以设置join超时xxx.join(3000),即3s后线程进入就绪态。
5.notifyAll:来着黑暗寒冬的随从们,仆人们,士兵们,听从克尔苏加德的召唤吧!


2.简单比较
item 从属 是否释放锁 状态转变为 异常
sleep Thread 静态方法 NO 阻塞 InterruptedException
wait Object 公共方法 YES 等待队列 IllegalMonitorStateException+InterruptedException
notify/notifyAll Object 公共方法 -- 同步队列 IllegalMonitorStateException
join Thread 公共方法 NO 阻塞 InterruptedException
yield Thread 公共方法 NO 可执行态

线程篇2:[- sleep、wait、notify、join、yield -]相关推荐

  1. 线程join_Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)

    点击上方"Coder编程",选择"置顶公众号" 技术文章第一时间送达! 并发编程.png 每天进步一点,不做curd工程师与Api调用工程师 欢迎访问 个人博客 ...

  2. java 关闭守护线程_Java并发编程之线程生命周期、守护线程、优先级、关闭和join、sleep、yield、interrupt...

    Java并发编程中,其中一个难点是对线程生命周期的理解,和多种线程控制方法.线程沟通方法的灵活运用.这些方法和概念之间彼此联系紧密,共同构成了Java并发编程基石之一. Java线程的生命周期 Jav ...

  3. 锁与并发工具包与线程池与LockSupport与Fork/Join框架与并行流串行流与阻塞队列与JPS,jstack命令查看死锁查看线程状态与AQS个人笔记九

    朝闻道,夕死可矣 本文共计 86564字,估计阅读时长1小时 点击进入->Thread源码万字逐行解析 文章目录 本文共计 86564字,估计阅读时长1小时 一锁 二Java中13个原子操作类 ...

  4. Android面试题线程篇

    Android面试题线程篇,由本人整理汇总,后续将推出系列篇,如果喜欢请持续关注和推荐. 开启线程的三种方式? java有三种创建线程的方式,分别是继承Thread类.实现Runable接口和使用线程 ...

  5. Java线程基础(13):wait()和notify()

    目录 简介 一.wait()和notify()含义 二.标准代码示例 创建两个线程Thread0和Thread1. 代码实现: 运行流程详解 三.什么时候释放锁-wait().notify() 四.用 ...

  6. java多线程wait notify join

    wait notify 几个注意点: wait 与 notify/notifyAll 方法必须在同步代码块中使用,即要先对调用对象加锁. 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进 ...

  7. JAVA线程间协作:wait.notify.notifyAll

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  8. 理解Python并发编程一篇就够了 - 线程篇

    目录 前言 GIL 同步机制 1. Semaphore(信号量) 2. Lock(锁) 3. RLock(可重入锁) 4. Condition(条件) 5. Event 6. Queue 线程池 前言 ...

  9. linux线程篇,linux线程篇 (二) 线程的基本操作

    线程 进程 标识符 pthread_t pid_t 获取ID pthread_self() getpid() 创建 pthread_create() fork 销毁 pthread_exit() ex ...

最新文章

  1. div 相同属性提取
  2. 因特尔显卡自定义分辨率_蓝宝石RX 5600XT 6G D6 白金版OC显卡评测:两千价位段好选择...
  3. 安卓绿色联盟两项免费福利重磅发布:EMUI9.0和绿色应用2.0测试能力
  4. 学习日志---哈夫曼树相关算法
  5. 计算机科学班(原acm班),计算机科学创新实验班(以下简称ACM班)培养计划.doc
  6. 【Quartz】插件的使用
  7. 2020亚太内容分发大会 阿里云荣获“边缘计算领航企业”奖
  8. git am 部分发生冲突的处理
  9. Snagit 2019 快速截图
  10. postgresql 存储过程处理json字符串
  11. 如何安装最纯净的win7系统
  12. 【入门】倒序输出一个四位整数
  13. SpringBoot + FreeMarker + FlyingSaucer 实现PDF在线预览、打印、下载
  14. 爬虫 -- 王者荣耀爬虫,爬取每个英雄的皮肤图片
  15. 网络划分之IP地址计算器
  16. peewee mysql_peewee基本使用
  17. 安装VC 6.0,出现 DOSX.EX must be in your AUTOEXEC.NT的信息
  18. [团队管理]从《亮剑》看团队建设之二——PM如何与组员合作
  19. Acrobat 虚拟打印机打印失败故障解决之一
  20. DG备库delay设置备库延时apply archivelog 但不延时传送归archivelog

热门文章

  1. CSDN如何转载别人的文章(最详细教程)
  2. 蓝桥杯之单片机设计与开发——第八届省赛_基于单片机的电子钟程序设计与调试
  3. 前端简介,head内标签
  4. Modelsim 仿真 DDR2 IP核 测试 和自定义仿真平台搭建 IP核仿真
  5. js现在的时间上增加小时分钟秒
  6. 如何在Mac上的iMovie剪辑中创建切换镜头效果?
  7. 机器学习实践——人员越界识别(基于Aidlux+Yolov5实现)
  8. SpringBoot 日期转换错误JSON parse error: Cannot deserialize value of type `java.time.LocalDateTime`
  9. 送给所有还未买房的技术朋友们——住房按揭贷款计算器
  10. 基于Python的ProcessOn思维导图一键备份