当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中, 有几种状态呢? 在API中 java.lang.Thread.State 这个枚举中给出了六种线程状态 初始(NEW):新创建了一个线程对象,但还没有调用start()方法 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running) 阻塞(BLOCKED):表示线程阻塞于锁 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断) 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回 终止(TERMINATED):表示该线程已经执行完毕



我们不需要去研究这几种状态的实现原理,我们只需知道在做线程操作中存在这样的状态。那我们怎么去理解这几 个状态呢,新建与被终止还是很容易理解的,我们就研究一下线程从Runnable(可运行)状态与非运行状态之间 的转换问题
Timed Waiting 线程状态图

BLOCKED 锁阻塞

Waiting 无限等待
一个正在无限期等待另一个线程执行一个特别的(唤醒)动作的线程处于这一状态
public class WaitingDemo {public static void main(String[] args) {Object lock = new Object();new Thread(new Runnable() {@Overridepublic void run() {synchronized (lock) {System.out.println("老板,来份牛排");try {lock.wait(); // 无限等待} catch (InterruptedException e) {e.printStackTrace();}System.out.println("-------- 开吃 --------");}}}).start();new Thread(new Runnable() {@Overridepublic void run() {synchronized (lock) {System.out.println("好咧,5号客人一份牛排");try {System.out.println("牛排制作中...");Thread.sleep(3000);// 调用notify方法,释放锁对象,让无限等待解除变成可运行lock.notify();} catch (InterruptedException e) {e.printStackTrace();}}}}).start();}}
⚠️注意:在使用等待唤醒机制,应该满足
- 同步使用的锁对象必须保证唯一
- 只有锁对象才能调用wait和notify方法
java.lang.Object跟线程有关的几点**
| 方法 | 说明 |
|---|---|
| void wait() | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待 |
| void wait(long timeout) | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待 写参数与Thread.sleep(2000)用法相似 |
| void notify() | 唤醒在此对象监视器上等待的单个线程,会继续执行wait方法之后的代码 |
| void notifyAll() | 唤醒在此对象监视器上等待的所有线程 |
等待唤醒机制
线程间通信
多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。比如:
- 线程A用来生成包子的
- 线程B用来吃包子的
包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,那么线程A与线程B之间就存在线程通信问题
为什么要处理线程间通信?
多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们 希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据
等待唤醒机制
等待唤醒是多个线程间的一种协作机制,谈到线程我们经常想到的是线程间的竞争(race),线程间也会有协作机制,wait/notify就是线程间的一种协作机制
- wait:线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时 的线程状态即是 WAITING。它还要等着别的线程执行一个特别的动作,也即是“通知(notify)”在这个对象 上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中
- notify:则选取所通知对象的 wait set 中的一个线程释放;例如,餐馆有空位置后,等候就餐最久的顾客最先 入座
- notifyAll:则释放所通知对象的 wait set 上的全部线程
⚠️注意:
- wait方法与notify方法必须要由同一个锁对象调用
- 因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程
- wait方法与notify方法是属于Object类的方法的
- 因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的
- wait方法与notify方法必须要在同步代码块或者是同步函数中使用
- 因为:必须要通过锁对象调用这2个方法 ```java import java.util.ArrayList; import java.util.Arrays; import java.util.Random;
//包子资源类 class Bun { String pier; String xianer; boolean hasBun = false; // 有没有面包 }
// 吃货线程类: class Foodie extends Thread { private final Bun bun;
public Foodie(final String name, final Bun bun) { super(name); this.bun = bun; }
@Override public void run() { while (true) { synchronized (bun) { if (bun.hasBun == false) { try { // 没有包子等待 bun.wait(); } catch (final InterruptedException e) { e.printStackTrace(); } } try { System.out.println(this.getName() + “:吃货正在吃…”); sleep(3000); System.out.println(“—————— 吃完了 ——————\n”); } catch (InterruptedException e) { e.printStackTrace(); } bun.hasBun = false; bun.notify(); } } } }
class BunShop extends Thread { private final Bun bun; // 创建一个包子变量
public BunShop(final String name, final Bun bun) { super(name); this.bun = bun; }
@Override public void run() { while (true) { synchronized (bun) { if (bun.hasBun == true) { try { // 有包子不用再做 Thread.sleep(1000); System.out.println(“还有面包,面包师傅休息(进入wait())”); bun.wait(); } catch (final InterruptedException e) { e.printStackTrace(); } }
// 没有的时候,开始做包子
System.out.println("------包子铺开始做包子------");
try {
sleep(new Random().nextInt(5000) + 2000);
} catch (final InterruptedException e) {
e.printStackTrace();
}
final ArrayList<Object> list = new ArrayList<>();
list.addAll(Arrays.asList("🐀", "🐂", "🐅", "🐇", "🐉", "🐍", "🐎", "🐏", "🐒", "🐓", "🐕", "🐖"));
bun.pier = (String) list.get(new Random().nextInt(12));
bun.xianer = "肉包子馅";
bun.hasBun = true;
System.out.println(this.getName() + ":" + bun.pier + bun.xianer + "包子做好了");
bun.notify(); // 唤醒等待线程
}
}
} }
// 测试类 public class Demo { public static void main(final String[] args) { final Bun bun = new Bun(); final BunShop bunshop = new BunShop(“包子铺类线程”, bun); final Foodie foodie = new Foodie(“吃货类线程”, bun); bunshop.start(); foodie.start(); } } ```
