Java线程控制详解:从创建到状态管理与中断机制
本文详解Java线程控制的完整流程,包括线程创建、生命周期状态(就绪、运行、阻塞、等待)的转换逻辑,以及利用Thread类方法进行线程调度、暂停、等待唤醒和安全中断的具体代码实现,帮助开发者掌握并发编程基础。
线程基本概念与资源模型
在深入线程控制之前,需明确并行(Parallelism)与并发(Concurrency)的区别。并行指多CPU核心同时处理不同任务;并发则是多个任务交替使用CPU核心以提升利用率。进程是系统资源分配的单位,拥有独立的内存空间和堆存储;而线程是CPU调度的基本单位,共享进程的堆和资源,但拥有独立的栈空间以保存方法调用和基本类型数据。
线程的生命周期与状态转换
Java线程在JVM中主要经历以下状态,状态的切换由JVM自动调度:
- New(新建):线程对象已创建但尚未启动。
- Runnable(可运行):包括Ready(就绪)和Running(运行)。线程具备执行条件或正在CPU上执行,采用时间片轮转算法调度。
- Blocked(阻塞):线程因等待锁等资源暂停执行,获得资源后转为就绪状态。
- Waiting(无限等待):线程主动等待其他线程通知,释放资源锁。如调用无参wait()或join(),直至被显式唤醒。
- Timed Waiting(计时等待):如调用sleep()或带超时参数的wait(),超时后自动进入就绪状态。
- Terminated(终止):线程执行完毕或发生异常退出。
线程的创建与启动
第1步:定义线程任务
Java提供两种定义线程的方式。推荐使用实现 Runnable 接口,以避免单继承限制并更好地分离任务逻辑与线程容器。
// 方式一:继承 Thread 类
class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
// 方式二:实现 Runnable 接口(推荐)
class MyTask implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
第2步:启动线程
必须调用 start() 方法启动线程,该方法会通知JVM安排新线程执行 run()。直接调用 run() 仅作为普通方法在当前线程执行,不会创建新线程。每个线程实例只能启动一次。
// 启动继承Thread的子类
MyThread t1 = new MyThread();
t1.start();
// 启动基于Runnable的线程
MyTask task = new MyTask();
Thread t2 = new Thread(task, "Custom-Thread");
t2.start();
线程调度与控制方法
第3步:线程让步 (Yield)
调用 Thread.yield() 可使当前线程从Running状态回到Runnable状态,让出CPU给同等优先级的其他线程。但这仅是建议,JVM不保证立即切换。
public void run() {
for (int i = 0; i < 10; i++) {
Thread.yield(); // 提示JVM进行线程调度
// ... 执行任务
}
}
第4步:线程睡眠 (Sleep)
Thread.sleep(millis) 使当前线程进入Timed Waiting状态指定的毫秒数。注意:Sleep不会释放对象锁,其他线程无法访问其同步资源。调用需处理 InterruptedException。
try {
Thread.sleep(1000); // 暂停1秒,保持锁
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
}
第5步:等待与唤醒 (Wait/Notify)
这是线程间通信的核心机制,必须在 synchronized 块中使用:
- wait():当前线程释放对象锁,进入对象的等待池。可选超时参数
wait(long)实现计时等待。调用时会自动释放持有的锁。 - notify():随机唤醒等待池中一个处于Waiting状态的线程,使其重新竞争锁。若需所有线程都参与竞争,使用
notifyAll()。
重要规则:调用wait()前必须持有该对象的锁;notify()后不会立即释放锁,需等到当前synchronized块结束才释放,被唤醒线程需在锁释放后重新获取才能继续执行。
synchronized (obj) {
while (condition) {
obj.wait(); // 等待条件满足,释放锁
}
// 执行逻辑
obj.notify(); // 通知其他线程
}
线程的中断与终止
stop() 方法已过时且危险,可能导致数据不一致。现代Java推荐使用中断标志位进行协作式终止。
t.interrupt():设置线程t的中断标志为true。如果线程正在wait/sleep,会抛出InterruptedException并清除中断标志。t.isInterrupted():检查中断标志是否为true,不清除标志。Thread.interrupted():静态方法,检查当前线程中断标志并清除标志。
最佳实践是在循环或长时间运行任务中检查中断状态,一旦检测到中断则优雅退出:
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
// 可能抛出的工作
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 重新设置中断标志以便后续捕获
break;
}
}
}
以上就是Java线程控制与状态管理的详细内容,更多关于Java并发编程实战的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









