源本科技 | 码上会

Java 多线程入门

2026/01/29
69
0

学习目标

  • 理解 Java 线程的基本概念及其在并发编程中的作用

  • 掌握两种创建线程的方式:继承 Thread 类与实现 Runnable 接口

  • 了解 Java 线程的生命周期及其状态转换

  • 区分 start()run() 方法的行为差异

  • 认识多线程带来的性能优势与资源利用效率提升


什么是线程

Java 线程是程序中最小的执行单元。它是一种轻量级的子进程,能够独立运行,但与所属进程共享同一内存空间。这种机制允许多个任务并发执行,从而提升程序的整体效率。


创建线程的两种方式

在 Java 中,可以通过以下两种标准方式创建线程:

1. 继承 Thread

步骤如下:

  • 定义一个类继承 java.lang.Thread

  • 重写 run() 方法,在其中编写线程要执行的逻辑

  • 创建该类的实例,并调用 start() 方法启动线程

class MyThread extends Thread {
    @Override
    public void run() {
        String str = "线程已开始运行...";
        System.out.println(str);
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start(); // 启动新线程
    }
}

输出:

线程已开始运行...

注意:只有调用 start() 才会真正启动一个新线程;若直接调用 run(),则只是普通方法调用,不会并发执行。


2. 实现 Runnable 接口

推荐

步骤如下:

  • 定义一个类实现 java.lang.Runnable 接口

  • 重写 run() 方法

  • 创建该类的实例,并将其作为参数传入 Thread 构造器

  • 调用 Thread 对象的 start() 方法

class MyTask implements Runnable {
    @Override
    public void run() {
        String str = "线程正在顺利运行";
        System.out.println(str);
    }
}

public class Main {
    public static void main(String[] args) {
        MyTask task = new MyTask();
        Thread t1 = new Thread(task); // 将 Runnable 任务包装进 Thread
        t1.start();
    }
}

输出:

线程正在顺利运行

最佳实践建议
优先使用 Runnable 接口,因为 Java 不支持多重继承。如果你的类已经继承了其他父类,则无法再继承 Thread,此时 Runnable 是唯一选择。


线程的生命周期

一个 Java 线程在其生命周期中会经历多个状态。这些状态由 JVM 自动管理,开发者可通过 API 观察或影响其转换。

以下是线程的六种主要状态:

  1. 新建(New):线程对象已创建,但尚未调用 start()

  2. 可运行(Runnable):已调用 start(),等待 CPU 调度执行(包括正在运行和就绪状态)

  3. 阻塞(Blocked):尝试获取已被其他线程持有的锁而被阻塞

  4. 等待(Waiting):调用 wait()join()LockSupport.park() 后无限期等待

  5. 计时等待(Timed Waiting):调用 sleep()、带超时的 wait(timeout) 等方法后进入有限时间等待

  6. 终止(Terminated):线程执行完毕或因异常退出


start()run()

这是初学者常混淆的关键点:

方法

行为

run()

普通方法调用,在当前线程中顺序执行,不会创建新线程

start()

启动一个新线程,JVM 会在新线程中自动调用 run(),实现并发执行

示例对比

class DemoThread extends Thread {
    @Override
    public void run() {
        System.out.println("当前线程: " + Thread.currentThread().getName());
    }
}

public class Main {
    public static void main(String[] args) {
        DemoThread t = new DemoThread();

        // 直接调用 run() —— 在主线程中执行
        t.run(); 

        // 调用 start() —— 在新线程中执行
        t.start();
    }
}

可能输出:

当前线程: main
当前线程: Thread-0

Thread 类简介

Thread 是 Java 并发编程的核心类,定义如下:

public class Thread extends Object implements Runnable

每个 Thread 实例代表一个独立的执行流。它提供了丰富的控制方法,如:

  • start():启动线程

  • join():等待线程结束

  • sleep(long millis):使当前线程休眠

  • interrupt():中断线程

  • isAlive():检查线程是否仍在运行


多线程的优势

  1. 提升性能
    多核 CPU 上,多个线程可并行处理任务,显著缩短总执行时间。

  2. 高效利用资源
    线程共享进程内存(如堆、方法区),避免了进程间通信的开销。

  3. 增强响应性
    在 GUI 应用或 Web 服务中,主线程可保持界面响应,后台线程处理耗时操作(如文件读写、网络请求)。


重点总结

  • Java 线程是并发执行的基本单位,通过 Thread 类或 Runnable 接口创建

  • 必须使用 start() 启动线程,直接调用 run() 无法实现并发

  • 线程有六种生命周期状态,理解状态转换有助于调试并发问题

  • 优先选择 Runnable 接口方式,更符合面向对象设计原则且支持类继承复用

  • 多线程能提升程序性能、资源利用率和用户体验,但也需注意线程安全问题(后续课程将深入探讨)


思考题

  1. 为什么实现 Runnable 接口比继承 Thread 类更受推荐?请从 Java 语言特性和设计原则角度分析。

  2. 如果在一个线程中直接调用另一个线程对象的 run() 方法,会发生什么?这与调用 start() 有何本质区别?

  3. 假设你正在开发一个下载管理器,需要同时下载多个文件。你会如何设计线程模型?是否所有下载任务都应放在独立线程中?为什么?