在现代软件开发中,多线程编程是提升程序性能、实现并发处理的核心技术之一。Java 从诞生之初就对多线程提供了强大的支持,使得开发者可以轻松地编写并发程序。本文将详细介绍 Java 中创建多线程的三种经典方式:继承 Thread 类、实现 Runnable 接口,以及实现 Callable 接口。


一、继承 Thread 类

最直观的创建线程方式是通过继承 java.lang.Thread 类,并重写其 run() 方法。当调用线程的 start() 方法时,JVM 会自动调用 run() 方法来执行线程的任务。

示例代码:

import java.util.Random;

public class MyThread extends Thread {
    private static final Random RANDOM = new Random();

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName() + " : " + i);
            try {
                // 模拟任务执行时间,随机休眠0~100毫秒
                Thread.sleep(RANDOM.nextInt(100));
            } catch (InterruptedException e) {
                System.out.println(getName() + " 被中断");
                Thread.currentThread().interrupt(); // 恢复中断状态
            }
        }
    }
}

// 测试类
public class ThreadCreationDemo {
    public static void main(String[] args) {
        System.out.println("主线程启动");

        // 创建并启动3个线程
        for (int i = 0; i < 3; i++) {
            new MyThread().start();
        }

        System.out.println("主线程结束");
    }
}

说明:

  • getName() 获取线程名称(默认为 Thread-0, Thread-1 等)。
  • Thread.sleep() 用于模拟耗时操作。
  • 注意捕获 InterruptedException 并处理中断状态。

⚠️ 缺点:由于 Java 不支持多继承,继承 Thread 类后无法再继承其他类,灵活性较差。


二、实现 Runnable 接口

更推荐的方式是实现 java.lang.Runnable 接口。Runnable 只定义了一个 run() 方法,表示可执行的任务。通过将 Runnable 实例传递给 Thread 构造函数来创建线程。

示例代码(使用 Lambda 表达式):

import java.util.Random;

public class RunnableDemo {
    public static void main(String[] args) {
        System.out.println("主线程启动");

        // 使用 Lambda 表达式创建 Runnable 任务
        Runnable task = () -> {
            Random random = new Random();
            String threadName = Thread.currentThread().getName();
            for (int i = 0; i < 10; i++) {
                System.out.println(threadName + " : " + i);
                try {
                    Thread.sleep(random.nextInt(100));
                } catch (InterruptedException e) {
                    System.out.println(threadName + " 被中断");
                    Thread.currentThread().interrupt();
                }
            }
        };

        // 创建3个线程并启动
        for (int i = 0; i < 3; i++) {
            new Thread(task).start();
        }

        System.out.println("主线程结束");
    }
}

说明:

  • 使用 Lambda 表达式使代码更简洁。
  • 多个线程可以共享同一个 Runnable 实例,适合任务相同但需并发执行的场景。
  • 解耦了任务与线程,提高了代码的灵活性和可复用性。

推荐使用:这是最常用的多线程创建方式。


三、实现 Callable 接口

Callable 接口与 Runnable 类似,但功能更强大。它允许任务返回结果,并可以抛出受检异常。Callable 通常配合 FutureTask 使用。

示例代码:

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableDemo {
    public static void main(String[] args) {
        System.out.println("主线程启动");

        Random random = new Random();

        for (int i = 0; i < 3; i++) {
            // 创建 Callable 任务:返回一个0~9之间的随机整数
            Callable<Integer> task = () -> {
                int result = random.nextInt(10);
                System.out.println(Thread.currentThread().getName() + " 生成了: " + result);
                return result;
            };

            // 将 Callable 包装为 FutureTask
            FutureTask<Integer> futureTask = new FutureTask<>(task);

            // 创建线程并启动
            new Thread(futureTask).start();

            try {
                // 获取任务执行结果(阻塞直到结果可用)
                Integer result = futureTask.get();
                System.out.println("获取到结果: " + result);
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }

        System.out.println("主线程结束");
    }
}

说明:

  • Callable<V>call() 方法有返回值(类型为 V),且可抛出异常。
  • FutureTaskFuture 接口的实现类,用于获取异步计算结果。
  • futureTask.get() 会阻塞当前线程,直到任务完成并返回结果。

适用场景:需要获取线程执行结果或处理异常时使用。


三种方式对比

方式是否有返回值是否可抛异常推荐程度说明
继承 Thread❌ 否❌ 否简单但不灵活
实现 Runnable❌ 否❌ 否⭐⭐⭐⭐最常用,推荐
实现 Callable✅ 是✅ 是⭐⭐⭐⭐需要结果时使用

总结

本文介绍了 Java 多线程的三种创建方式:

  1. 继承 Thread:简单直观,但不推荐。
  2. 实现 Runnable 接口:解耦任务与线程,推荐使用。
  3. 实现 Callable 接口:可获取返回值,适用于需要结果的场景。

在实际开发中,建议优先使用 RunnableCallable,避免继承 Thread 类。随着 Java 并发工具类(如线程池 ExecutorService)的发展,直接创建线程的方式已逐渐被更高级的抽象所取代,但理解这三种基础方式仍是掌握 Java 多线程的基石。