源本科技 | 码上会

Java 中的主线程

2026/01/29
53
0

学习目标

  • 理解主线程在 Java 程序中的角色与生命周期

  • 掌握如何获取并控制主线程(如修改名称、优先级等)

  • 了解主线程与 main() 方法的关系

  • 认识线程优先级的继承机制

  • 理解单线程死锁的成因与示例


什么是主线程

当一个 Java 程序启动时,Java 虚拟机(JVM)会自动创建一个线程,这个线程就是主线程(Main Thread)。它是程序执行的起点,负责:

  • 验证并调用 public static void main(String[] args) 方法

  • 初始化主类及其依赖

  • 启动其他子线程(如果有的话)

  • 执行程序的主要逻辑或协调任务

从 JDK 6 开始,所有独立运行的 Java 应用程序必须包含 main() 方法,否则无法启动。


核心特性

  • 自动创建:无需显式实例化,JVM 在启动时创建

  • 默认名称为 "main"

  • 默认优先级为 5(Thread.NORM_PRIORITY

  • 是所有用户线程的“父线程”:新创建的线程会继承主线程的优先级

  • 通常应最后结束:常用于执行资源清理、日志关闭等收尾工作


如何获取并控制主线程

通过 Thread.currentThread() 方法可以获取当前正在执行的线程引用。在 main() 方法中调用它,即可获得主线程对象。

示例:控制主线程属性

public class MainThreadControl {

    public static void main(String[] args) {
        // 获取主线程引用
        Thread mainThread = Thread.currentThread();

        // 查看默认属性
        System.out.println("当前线程名称: " + mainThread.getName());
        System.out.println("主线程优先级: " + mainThread.getPriority());

        // 修改名称和优先级
        mainThread.setName("PrimaryWorker");
        mainThread.setPriority(Thread.MAX_PRIORITY); // 设置为 10

        System.out.println("修改后名称: " + mainThread.getName());
        System.out.println("新优先级: " + mainThread.getPriority());

        // 主线程执行任务
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程执行中...");
        }

        // 创建子线程
        Thread child = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                System.out.println("子线程执行中...");
            }
        });

        // 子线程初始优先级继承自主线程(此时为 10)
        System.out.println("子线程初始优先级: " + child.getPriority());

        // 调整子线程优先级
        child.setPriority(Thread.MIN_PRIORITY); // 设为 1
        System.out.println("子线程新优先级: " + child.getPriority());

        child.start();
    }
}

输出示例:

当前线程名称: main
主线程优先级: 5
修改后名称: PrimaryWorker
新优先级: 10
主线程执行中...
主线程执行中...
主线程执行中...
子线程初始优先级: 10
子线程新优先级: 1
子线程执行中...
子线程执行中...
子线程执行中...

注意:子线程在创建时自动继承创建者线程的优先级,之后可单独修改。


主线程与 main()

概念

说明

main() 方法

Java 程序的入口点,由 JVM 调用

主线程

执行 main() 方法的线程实体

  • JVM 启动后,首先创建主线程

  • 主线程负责查找并执行 main() 方法

  • 所有在 main() 中直接编写的代码都在主线程中运行

  • main() 方法执行完毕且无其他非守护线程存活,JVM 退出


单线程死锁

一个特殊案例

虽然死锁通常涉及多个线程互相等待,但仅用主线程也能制造死锁

死锁示例

public class SingleThreadDeadlock {

    public static void main(String[] args) {
        try {
            System.out.println("即将进入死锁...");

            // 主线程等待自己结束 —— 不可能完成!
            Thread.currentThread().join();

            // 此行永远不会执行
            System.out.println("这行代码永远不会输出");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

死锁原理

  • thread.join() 的作用是:当前线程等待 thread 执行完毕后再继续

  • 当主线程调用 Thread.currentThread().join() 时,相当于说:“我等我自己结束”

  • 但“自己结束”需要先执行完后续代码,而后续代码又被 join() 阻塞

  • 形成自相矛盾的循环等待,即死锁

此程序会一直挂起,除非被外部强制终止(如 Ctrl+C)


线程优先级说明

Java 线程优先级范围为 1 到 10:

  • Thread.MIN_PRIORITY = 1

  • Thread.NORM_PRIORITY = 5(默认值)

  • Thread.MAX_PRIORITY = 10

注意:优先级只是建议性提示,实际调度由操作系统决定。在某些系统(如 Linux)上,Java 优先级可能被映射到有限的调度级别,效果不明显。


最佳实践

  1. 避免在主线程中执行长时间阻塞操作(如 I/O、复杂计算),以免影响程序响应

  2. 合理使用子线程处理并发任务,主线程可专注于协调与监控

  3. 不要依赖线程优先级控制执行顺序,应使用同步机制(如 synchronizedCountDownLatch 等)

  4. 确保主线程在退出前等待关键子线程完成(可通过 join() 实现)

  5. 谨慎使用 join(),防止意外死锁


重点总结

  • 主线程是 JVM 自动创建的程序入口线程

  • 可通过 Thread.currentThread() 获取并控制主线程

  • 子线程默认继承创建者线程的优先级

  • main() 方法由主线程执行,是程序逻辑的起点

  • 即使只有一个线程,不当使用 join() 也可能导致死锁

  • 主线程通常应最后退出,以确保程序完整执行


思考题

  1. 如果 main() 方法执行完毕,但还有非守护线程在运行,JVM 会退出吗?为什么?

  2. 为什么说“线程优先级不能保证执行顺序”?在什么场景下优先级可能失效?

  3. 除了 join(),还有哪些方式可以让主线程等待子线程完成?各自的优缺点是什么?