第3章

🔄 线程生命周期

深入理解线程的生命周期和状态转换,掌握线程状态的查看和监控方法

学习目标

线程状态详解

在Java中,线程的生命周期由Thread.State枚举定义,包含6个状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。理解这些状态及其转换条件是掌握多线程编程的基础。

线程状态转换图

NEW
RUNNABLE
TERMINATED
BLOCKED
RUNNABLE
WAITING
TIMED_WAITING
RUNNABLE

六种线程状态

NEW(新建)
线程对象已创建但尚未调用start()方法。此时线程还没有开始执行。
RUNNABLE(可运行)
线程正在Java虚拟机中执行,但可能正在等待操作系统的其他资源,如CPU时间片。
BLOCKED(阻塞)
线程被阻塞等待监视器锁,通常发生在synchronized代码块或方法中。
WAITING(等待)
线程无限期等待另一个线程执行特定操作,如调用Object.wait()或Thread.join()。
TIMED_WAITING(超时等待)
线程等待指定时间,如Thread.sleep()、Object.wait(timeout)等。
TERMINATED(终止)
线程执行完毕或因异常而终止,run()方法执行完成。
重要提示

RUNNABLE状态在Java中包含了操作系统层面的READY和RUNNING状态,这是因为Java无法精确区分线程是在等待CPU时间片还是正在执行。

状态转换条件

线程状态之间的转换有明确的触发条件,理解这些条件有助于我们更好地控制线程的行为。

主要状态转换

// 演示线程状态转换
public class ThreadStateDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                System.out.println("线程开始执行");
                Thread.sleep(2000); // TIMED_WAITING
                System.out.println("线程执行完毕");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        System.out.println("创建后状态: " + thread.getState()); // NEW
        
        thread.start();
        System.out.println("启动后状态: " + thread.getState()); // RUNNABLE
        
        Thread.sleep(100);
        System.out.println("睡眠中状态: " + thread.getState()); // TIMED_WAITING
        
        thread.join();
        System.out.println("结束后状态: " + thread.getState()); // TERMINATED
    }
}

线程调度机制

Java虚拟机采用抢占式调度模型,线程的执行顺序由操作系统的线程调度器决定。理解调度机制有助于我们编写更高效的多线程程序。

调度策略

抢占式调度
高优先级线程可以抢占低优先级线程的CPU时间,但优先级只是调度的参考,不保证执行顺序。
时间片轮转
同优先级线程采用时间片轮转方式,每个线程获得相等的CPU时间片。
公平调度
现代JVM尽量保证线程调度的公平性,避免线程饥饿现象。
注意事项

不要依赖线程优先级来控制程序逻辑,因为不同操作系统的调度策略可能不同。应该使用同步机制来确保程序的正确性。

线程监控工具

Java提供了多种工具来监控和分析线程状态,这些工具对于调试和性能优化非常重要。

常用监控工具

jstack
命令行工具,用于生成线程堆栈快照,分析线程状态和死锁问题。
jstack <pid>
jconsole
图形化监控工具,可以实时查看线程状态、内存使用情况等。
VisualVM
功能强大的可视化工具,提供线程分析、性能分析等功能。
// 程序内监控线程状态
public class ThreadMonitor {
    public static void monitorThread(Thread thread) {
        System.out.println("线程名称: " + thread.getName());
        System.out.println("线程状态: " + thread.getState());
        System.out.println("是否存活: " + thread.isAlive());
        System.out.println("是否守护线程: " + thread.isDaemon());
        System.out.println("线程优先级: " + thread.getPriority());
    }
    
    public static void printAllThreads() {
        ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
        while (rootGroup.getParent() != null) {
            rootGroup = rootGroup.getParent();
        }
        
        Thread[] threads = new Thread[rootGroup.activeCount()];
        rootGroup.enumerate(threads);
        
        for (Thread thread : threads) {
            if (thread != null) {
                System.out.println(thread.getName() + ": " + thread.getState());
            }
        }
    }
}

优雅停止线程

正确停止线程是多线程编程中的重要技能。Java提供了interrupt机制来实现线程的优雅停止,避免使用已废弃的stop()方法。

停止线程的方法

interrupt机制
通过调用interrupt()方法设置中断标志,线程检查标志后自行停止。
标志位控制
使用volatile布尔变量作为停止标志,线程定期检查标志状态。
资源清理
在线程停止前确保释放所有资源,如关闭文件、网络连接等。
// 使用interrupt机制优雅停止线程
public class GracefulShutdownDemo {
    private static class InterruptibleTask implements Runnable {
        @Override
        public void run() {
            try {
                while (!Thread.currentThread().isInterrupted()) {
                    // 执行任务
                    System.out.println("执行任务中...");
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                // 恢复中断状态
                Thread.currentThread().interrupt();
                System.out.println("线程被中断,开始清理资源");
            } finally {
                // 清理资源
                cleanup();
            }
        }
        
        private void cleanup() {
            System.out.println("资源清理完成");
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        Thread worker = new Thread(new InterruptibleTask());
        worker.start();
        
        // 运行3秒后停止
        Thread.sleep(3000);
        worker.interrupt();
        
        // 等待线程结束
        worker.join();
        System.out.println("主线程结束");
    }
}
最佳实践
  • 永远不要使用Thread.stop()方法,它已被废弃且不安全
  • 在可能阻塞的操作前检查中断状态
  • 捕获InterruptedException后要恢复中断状态
  • 使用finally块确保资源得到正确清理
  • 为长时间运行的任务提供取消机制
上一章:线程基础操作 返回目录 下一章:线程安全问题