一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
并发的基础就是多线程,我们先来了解线程的相关状态
在Thread中有一个枚举类,列举了线程的6个状态.
其实应该是7种状态,少了一个就绪状态,,Java直接将就绪和运行中归为一类
public enum State {
// 创建状态 : 尚未启动的线程
NEW,
// 运行状态 : 包括就绪状态READY和运行状态RUNNING
RUNNABLE,
// 阻塞状态 : 线程等待锁,线程正在等待获取锁去进入同步方法/同步块
// 只有synchronized修饰的才能进入BLOCKED状态
BLOCKED,
/**
*等待状态:
不指定超时时间的等待方法
wait,join,park ,这些方法会被
**/
WAITING,
/**
* 超时等待状态:
指定超时时间的等待方法.
包括sleep,wait,parkNanos,join等
**/
TIMED_WAITING,
// 中止状态 :
// 任务执行完 异常退出
TERMINATED;
}
注意点:
1.只有synchronized修饰的才能进入BLOCKED状态 :
LOCK为什么不行:LOCK的底层是AQS,依赖park,LOCK 在同步队列中使用的park,状态变成了WAITING,没有BLOCKED状态
2.将操作系统的READY和RUNNING状态合并到了RUNNABLE中
3.触发WAITING状态的动作都是需要唤醒(手动或者隐式) 的.唤醒方法即从WAITING -> RUNNABLE
wait,join,park 这些方法都是有唤醒条件的.因此
4.BLOCKED 和 WAITING 的 关系
在sync或者lock中,我们有两个队列,一个是同步队列,一个是等待队列,可以与两个状态对应.
Synchronized当调用wait/方法时,线程会进入等待队列,状态变成WAITING,唤醒进入同步队列,等待获取锁,状态变成BLOCKED.当获取成功,再变成RUNNABLE.BLOCK相当于WAITING的后续处理,WAITING与RUNNABLE的中间人
wait/notify
Object的方法
wait和notify需要获得锁,即在sync代码块中使用。当notify执行完毕才会去唤醒wait
线程竞争获取锁后才能在wait()处返回
线程执行wait之后会进入等待队列,当被notify通知后就会进入同步队列来竞争锁。
sleep/yield
两个都是Thread的方法
sleep是让当前线程休眠,主动让出CPU调度。从运行态变成阻塞状态(其他阻塞)。
sleep不会释放同步资源锁,因此超时后会进入就绪状态
yield是让步,让线程从运行态变成就绪状态,尽量让其他就绪态的线程获得调度,但是不保证
sleep(0) 和 yield() 的作用一样,都是将CPU执行权让出
park
Unsafe.park() 调用本地方法的park可以执行挂起操作
Unsafe.unpark() park的许可,从挂起返回.
unpark可以在park之前,相当于一一抵消.但是如果操作再unpark之前,park之后就会形成死锁