基础 | 并发编程 - [线程状态 & 中断]
@
§1 线程状态
| 含义 | 是否存活 | 是否可以占有 CPU 是否可以自动解除阻塞 |
已占有CPU | 涉及到的池 | 说明 | |
|---|---|---|---|---|---|---|
| New | 新建 | √ | × | × | - | 刚刚创建,尚未 start() |
| Runnable | 就绪 | √ | √ | × | 可运行线程池 | 已 start(),等待获取 CPU 使用权 |
| Running | 运行 | √ | √ | √ | - | |
| Blocked | 阻塞 | √ | × | × | - | 放弃 CPU 使用权 |
| 等待阻塞 | √ | × | × | 等待池 | 已 wait() |
|
| 同步阻塞 | √ | √ | × | 锁池 | 抢锁没抢到,等待锁释放 | |
| 其他阻塞 | √ | √ | × | - | 已 sleep()、join()、IO 等 |
|
| Dead | 死亡 | × | × | × | - | 完成或异常 |

§2 用户态、内核态
区别
CPU 处于的状态不同
CPU 状态的不同,影响 CPU 执行指令的权限
为什么会划分用户态、内核态
- 程序最终是由 CPU 指令执行的
- CPU 指令中,有些比较上层、比较安全,有些比较底层、比较危险
因此,不可能对应用程序直接开放所有 CPU 指令 - 于是,CPU 指令被划分为不同的级别
- intel 体系中,划分了 4 个级别,从高到低依次
- Ring0,内核指令
- Ring1,底层硬件驱动指令
- Ring2,上层硬件驱动指令
- Ring3,用户应用指令
- Linux 中只划分 2 层 Ring0、Ring3
- intel 体系中,划分了 4 个级别,从高到低依次
- 线程处于用户态还是内核态,取决于线程 CPU 是在执行哪个级别的指令
- Ring0,对应内核态,处理
- Ring3,对应用户态
什么时候发生用户态、内核态的切换
下面场景线程会切换至内核态,但本质上将下列情况都是 中断
- 用户应用通过 系统调用 使用内核态指令时
- 内核态的指令不能直接由用户应用调用,因为危险
- 但不能完全禁止用户应用调用内核态指令,因为确实会用到,比如磁盘读写
- 只能折中的通过 系统调用 的方式迂回
- 系统调用本质上属于中断,只不过是软件中断
- 用户应用发生异常时
- 用户应用涉及到的外设中断时
§2 线程停止 & 中断
推荐的停止线程的方式
示例代码(通过中断:先中断,处理中断时停止)
public void run(){
while(true){
if(Thread.currentThread().isInterrupted()){
//结束线程
return;
}
try{
//do sth
Thread.sleep(2000);
}catch(InterruptedException e){
//结束线程
return;
}
}
}
- 线程只应该由自己停止或中断自己
因此Thread.stop、Thread.suspend、Thread.resume都过期了 - java 中无法立即停止一个线程
- 中断是用于停止线程的 协商机制
- 中断的具体过程没有 java 原生语法支持
即需要自己实现 Thread.interrupt仅将线程的中断标志位置为 true,推荐的停止线程的方式
所以对可能中断的线程,需要监听此标志位,发现它为 true 时,需要在业务中编码实现对应逻辑
中断方法
Thread.interrupt)中断方法,但作用仅限于设置标志位Thread.interrupted()静态方法,判断当前线程是否被中断,然后将中断标志位清除
这意味着,此方法认为,当调用此方法后,就会对当前线程的中断状态进行处理Thread.isInterrupted(),实例方法,判断当前线程是否被中断
子线程的停止
- 子线程是业务线程:线程停止不影响子线程
- 子线程是守护线程:线程停止子线程也停止
§3 线程通信
synchronized 锁:
- wait
- notigy
- notifyAll
线程:
- join
Lock(Condition):
- lock
- unlock
- await
- signal
- signalAll
BlockingQueue:
- 队列为空时,读阻塞
- 队列满载时,写阻塞

浙公网安备 33010602011771号