什么是 Runnable?
Runnable 是 Java 中一个非常重要的函数式接口,它位于 java.lang 包中,它只定义了一个抽象方法 run()。

@FunctionalInterface
public interface Runnable {
public abstract void run();
}
核心作用:
Runnable 接口为 Java 提供了一种“将任务与执行线程解耦”的机制,你可以把它想象成一个“任务说明书”或者“待办事项列表”。
- 任务: 你需要执行的代码逻辑,
run()方法里的内容。 - 执行者: 真正执行这个任务的线程。
Runnable 本身并不能运行,它只是一个可以被“执行”的任务描述,你需要将它交给一个 Thread 对象,由这个 Thread 对象去调用 run() 方法,从而在新的线程中执行任务。
为什么要使用 Runnable?(而不是继承 Thread)
在 Java 中实现多线程主要有两种方式:
- 继承
java.lang.Thread类。 - 实现
java.lang.Runnable接口。
通常情况下,更推荐使用 Runnable 接口,原因如下:

| 特性 | 继承 Thread 类 |
实现 Runnable 接口 |
|---|---|---|
| 类继承限制 | Java 是单继承的,一个类继承了 Thread 类就无法再继承其他父类。 |
灵活,一个类可以实现 Runnable 接口,同时还可以继承其他类或实现其他接口。 |
| 资源共享 | 不方便,如果多个线程需要操作同一份共享数据,继承 Thread 会让数据和线程强耦合。 |
非常方便,多个 Thread 对象可以共享同一个 Runnable 实例,从而轻松实现资源共享。 |
| 设计模式 | 违反了“组合优于继承”的设计原则。 | 符合“面向接口编程”和“组合”的设计思想,代码结构更清晰、更灵活。 |
Runnable 更符合 Java 的设计哲学,提供了更好的灵活性和代码复用性,尤其是在需要多个线程处理同一份数据的场景下。
如何使用 Runnable?(标准三步法)
使用 Runnable 创建并启动一个线程非常简单,遵循以下三个步骤:
步骤 1:创建一个 Runnable 任务类
创建一个类,实现 Runnable 接口,并重写 run() 方法,在 run() 方法中编写你希望在新线程中执行的代码。
// 步骤 1: 定义一个任务类,实现 Runnable 接口
class MyTask implements Runnable {
private String taskName;
public MyTask(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
// 这是线程要执行的任务代码
for (int i = 1; i <= 5; i++) {
System.out.println(taskName + " is running, count: " + i);
try {
// 模拟任务耗时
Thread.sleep(500); // 休眠 500 毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(taskName + " has finished.");
}
}
步骤 2:创建 Thread 对象,并将 Runnable 实例作为参数传入
Thread 类的构造函数可以接收一个 Runnable 对象。
// 步骤 2: 创建 Thread 对象,并将 Runnable 实例传递给它
MyTask task1 = new MyTask("Task-A");
Thread thread1 = new Thread(task1);
步骤 3:调用 start() 方法启动线程
非常重要的一点: 必须调用 thread.start() 方法,而不是 thread.run()。
thread.start(): 会创建一个新的线程,并让这个新线程去调用run()方法。这才是真正的多线程。thread.run(): 只是在当前线程中直接调用run()方法,不会创建新线程,代码会变成单线程顺序执行。
// 步骤 3: 调用 start() 方法启动线程 thread1.start();
完整代码示例
下面是一个完整的、可运行的示例,演示了如何使用 Runnable 启动两个线程。
// MyTask.java
class MyTask implements Runnable {
private String taskName;
public MyTask(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
// 获取当前执行的线程对象
Thread currentThread = Thread.currentThread();
System.out.println(taskName + " is running in thread: " + currentThread.getName());
for (int i = 1; i <= 5; i++) {
System.out.println(taskName + " count: " + i);
try {
Thread.sleep(500); // 休眠 500 毫秒,让线程调度有机会发生
} catch (InterruptedException e) {
System.out.println(taskName + " was interrupted.");
e.printStackTrace();
}
}
System.out.println(taskName + " has finished.");
}
}
// Main.java
public class RunnableDemo {
public static void main(String[] args) {
System.out.println("Main thread starts: " + Thread.currentThread().getName());
// 步骤 1 & 2: 创建任务和线程
MyTask task1 = new MyTask("Task Alpha");
MyTask task2 = new MyTask("Task Beta");
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
// 步骤 3: 启动线程
thread1.start();
thread2.start();
System.out.println("Main thread has finished starting the tasks.");
}
}
可能的输出结果(线程执行顺序不固定):
Main thread starts: main
Main thread has finished starting the tasks.
Task Alpha is running in thread: Thread-0
Task Alpha count: 1
Task Beta is running in thread: Thread-1
Task Beta count: 1
Task Alpha count: 2
Task Beta count: 2
Task Alpha count: 3
Task Beta count: 3
Task Alpha count: 4
Task Beta count: 4
Task Alpha count: 5
Task Alpha has finished.
Task Beta count: 5
Task Beta has finished.
从输出可以看到,main 线程、Thread-0 和 Thread-1 三个线程在并发执行,它们的打印顺序是交错的,这证明了多线程的特性。
进阶:使用 Lambda 表达式(Java 8+)
由于 Runnable 是一个函数式接口(只有一个抽象方法),我们可以使用 Java 8 引入的 Lambda 表达式来简化代码,无需创建一个单独的 MyTask 类。
public class RunnableLambdaDemo {
public static void main(String[] args) {
System.out.println("Main thread starts: " + Thread.currentThread().getName());
// 使用 Lambda 表达式直接创建 Runnable 任务
Thread thread1 = new Thread(() -> {
System.out.println("Lambda Task 1 is running in thread: " + Thread.currentThread().getName());
for (int i = 1; i <= 3; i++) {
System.out.println("Lambda Task 1 count: " + i);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Lambda Task 1 has finished.");
});
// 也可以给一个 Runnable 实例命名
Runnable task2 = () -> {
System.out.println("Lambda Task 2 is running in thread: " + Thread.currentThread().getName());
System.out.println("Lambda Task 2 is simple!");
};
thread1.start();
new Thread(task2, "Lambda-Thread-2").start(); // 启动线程并指定线程名
System.out.println("Main thread has finished starting the tasks.");
}
}
这种方式代码更简洁,特别适合于那些只需要简单执行一段逻辑的“一次性”任务。
Runnable 与 Future 和 ExecutorService 的结合(现代方式)
在实际的企业级应用中,我们通常不直接手动创建和启动 Thread 对象,而是使用 ExecutorService(线程池)来管理线程。Runnable 可以完美地与线程池配合使用。
ExecutorService 的 submit() 方法可以接收一个 Runnable 任务,并返回一个 Future 对象,虽然 Runnable 任务本身不返回结果,但 Future 可以用来跟踪任务的状态(如是否完成、是否被取消)。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ExecutorServiceRunnableDemo {
public static void main(String[] args) {
// 创建一个固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
System.out.println("Submitting tasks to the executor...");
// 提交一个 Runnable 任务
Runnable task1 = () -> {
System.out.println("Executor Task is running in: " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Executor Task has finished.");
};
// submit() 方法会立即返回,并返回一个 Future 对象
Future<?> future = executor.submit(task1);
// 可以检查任务是否完成
System.out.println("Task submitted. Is it done? " + future.isDone());
// 关闭线程池(非常重要!)
// shutdown() 会停止接受新任务,但会执行完队列中已有的任务
executor.shutdown();
System.out.println("Main thread continues...");
}
}
优点:
- 资源复用: 线程池避免了频繁创建和销毁线程的开销。
- 任务管理: 可以方便地管理任务队列、线程数量等。
- 生命周期管理: 提供了优雅的关闭机制。
| 特性 | 描述 |
|---|---|
| 核心概念 | Runnable 是一个任务,Thread 是执行者。 |
| 主要优点 | 灵活性高:避免了单继承限制。 资源共享:多个线程可共享同一个 Runnable 实例。设计优雅:符合组合优于继承的原则。 |
| 基本用法 | 创建实现 Runnable 的类 -> 2. 创建 Thread 对象并传入 Runnable -> 3. 调用 thread.start() |
| 现代实践 | 与 ExecutorService (线程池) 和 Future 结合使用,是生产环境中管理多线程任务的标准方式。 |
| 简化写法 | 使用 Lambda 表达式可以极大简化代码,无需显式定义实现类。 |
掌握 Runnable 是理解 Java 多线程编程的基石,它为你构建复杂、高效、可维护的并发应用程序打下了坚实的基础。
