Java Runnable 接口
最后修改时间:2025 年 4 月 13 日
java.lang.Runnable
接口是 Java 并发模型的基础组成部分。 它代表一个可以由线程执行的任务。 任何需要由线程执行的类的实例都应实现此接口。
Runnable 接口仅包含一个方法:run
。 当使用实现 Runnable 接口的对象创建线程时,启动线程会导致在该单独执行的线程中调用该对象的 run 方法。 这提供了一种定义应在线程中运行的代码的方式。
Runnable 接口定义
Runnable 接口非常简单,仅包含一个抽象方法。 这使其成为一个函数式接口,这意味着它可以与 Java 8 及更高版本中的 Lambda 表达式一起使用。 这是它的定义:
@FunctionalInterface public interface Runnable { public abstract void run(); }
上面的代码显示了 Runnable 接口的完整定义。 @FunctionalInterface
注解表示它可以与 Lambda 表达式一起使用。 该接口只需要实现 run 方法。
基本的 Runnable 实现
此示例演示了通过创建一个实现 Runnable 接口的类来实现该接口的最基本方法。 然后,我们使用 Runnable 创建一个 Thread 对象并启动它。
package com.zetcode; class MyRunnable implements Runnable { @Override public void run() { System.out.println("Thread is running..."); for (int i = 1; i <= 5; i++) { System.out.println("Count: " + i); try { Thread.sleep(500); // Pause for 500 milliseconds } catch (InterruptedException e) { System.out.println("Thread interrupted"); } } System.out.println("Thread finished."); } } public class Main { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); System.out.println("Main thread continues to run..."); } }
在此示例中,我们创建一个实现 Runnable 接口的 MyRunnable
类。 run
方法包含将在新线程中执行的代码。 我们使用 Runnable 实例创建一个 Thread 对象,并使用 thread.start
启动它。 主线程继续执行,而新线程并发运行。
带有 Lambda 表达式的 Runnable
使用 Java 8 的 Lambda 表达式,我们可以更简洁地实现 Runnable,而无需创建单独的类。 这是可能的,因为 Runnable 是一个仅包含一个抽象方法的函数式接口。
package com.zetcode; public class Main { public static void main(String[] args) { // Using lambda expression to implement Runnable Runnable runnable = () -> { System.out.println("Lambda thread running..."); for (int i = 0; i < 3; i++) { System.out.println("Working: " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Interrupted!"); } } System.out.println("Lambda thread done."); }; Thread thread = new Thread(runnable); thread.start(); System.out.println("Main thread doing other work..."); } }
此示例显示了如何使用 Lambda 表达式来实现 Runnable。 Lambda 提供了一种更简洁的方式来定义线程的行为,而无需创建单独的类。 语法 () -> { ... }
实现了 Runnable 接口的单个 run
方法。
使用 Runnable 的多个线程
我们可以使用相同的 Runnable 实例创建多个线程。 当我们希望多个线程执行相同的任务时,这非常有用。 每个线程将具有自己的执行路径。
package com.zetcode; class CounterRunnable implements Runnable { private final String name; public CounterRunnable(String name) { this.name = name; } @Override public void run() { for (int i = 1; i <= 5; i++) { System.out.println(name + ": " + i); try { Thread.sleep((long)(Math.random() * 1000)); } catch (InterruptedException e) { System.out.println(name + " interrupted"); } } System.out.println(name + " finished."); } } public class Main { public static void main(String[] args) { Runnable counter1 = new CounterRunnable("Counter 1"); Runnable counter2 = new CounterRunnable("Counter 2"); Thread thread1 = new Thread(counter1); Thread thread2 = new Thread(counter2); thread1.start(); thread2.start(); System.out.println("Main thread waiting for counters to finish..."); } }
在此示例中,我们创建了两个线程,它们共享相同的 Runnable 实现,但具有不同的名称。 每个线程使用随机睡眠间隔计数到 5,显示线程如何并发执行。 输出将显示来自两个线程的交错计数,展示了并发执行。
带有匿名类的 Runnable
在 Java 8 引入 Lambda 之前,匿名类通常用于简洁地实现 Runnable。 这种方法仍然有效,并且在需要访问封闭方法中的局部变量时非常有用。
package com.zetcode; public class Main { public static void main(String[] args) { final String message = "Hello from thread!"; // Using anonymous class to implement Runnable Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println(message); for (int i = 0; i < 3; i++) { System.out.println("Processing step " + (i + 1)); try { Thread.sleep(800); } catch (InterruptedException e) { System.out.println("Processing interrupted"); } } System.out.println("Processing complete."); } }); thread.start(); System.out.println("Main thread continues execution..."); } }
此示例演示了使用匿名类实现 Runnable。 匿名类可以访问 message
变量,因为它被声明为 final。 这种方法比 Lambda 更冗长,但在使用 Java 8 之前的版本或需要覆盖多个方法时是必需的。
带有方法引用的 Runnable
当您有一个与 Runnable 的 run 方法签名匹配的现有方法时,Java 8 方法引用提供了另一种简洁的实现 Runnable 的方法。 这对于不带参数且返回 void 的现有方法特别有用。
package com.zetcode; public class Main { public static void workerMethod() { System.out.println("Worker method executing in thread: " + Thread.currentThread().getName()); for (int i = 0; i < 4; i++) { System.out.println("Working on task " + (i + 1)); try { Thread.sleep(600); } catch (InterruptedException e) { System.out.println("Work interrupted"); } } System.out.println("Worker method completed."); } public static void main(String[] args) { // Using method reference to implement Runnable Thread thread = new Thread(Main::workerMethod); thread.start(); System.out.println("Main thread doing other tasks..."); } }
在此示例中,我们使用方法引用 Main::workerMethod
来实现 Runnable。 workerMethod
匹配 run
的签名(没有参数,void 返回),因此它可以直接用作 Runnable。 这种方法简洁明了,并且在您具有适合 Runnable 接口的现有方法时效果很好。
带有线程池的 Runnable
在实际应用中,通常最好使用线程池而不是直接创建线程。 Executor 框架提供了可以有效管理 Runnable 任务的线程池实现。
package com.zetcode; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; class Task implements Runnable { private final int taskId; public Task(int id) { this.taskId = id; } @Override public void run() { System.out.println("Starting task " + taskId + " in thread: " + Thread.currentThread().getName()); try { // Simulate work Thread.sleep(2000); } catch (InterruptedException e) { System.out.println("Task " + taskId + " interrupted"); } System.out.println("Completed task " + taskId); } } public class Main { public static void main(String[] args) { // Create a thread pool with 3 threads ExecutorService executor = Executors.newFixedThreadPool(3); // Submit 10 tasks to the pool for (int i = 1; i <= 10; i++) { Runnable task = new Task(i); executor.execute(task); } // Shutdown the executor when done executor.shutdown(); System.out.println("All tasks submitted to thread pool."); } }
此示例演示了将 Runnable 与线程池一起使用。 我们创建一个包含 3 个线程的池,并向其提交 10 个任务。 该池有效地管理任务执行,重用线程而不是为每个任务创建新线程。 请注意,只有 3 个任务并发运行,其他任务在队列中等待直到有线程可用。
Runnable 与 Thread
虽然 Runnable 和 Thread 都可以用于创建线程,但通常首选 Runnable,因为它将任务与线程执行机制分离。 这允许更灵活的设计,其中相同的任务可以以不同的方式执行。
package com.zetcode; // Approach 1: Extending Thread class MyThread extends Thread { @Override public void run() { System.out.println("Thread approach: " + getName()); } } // Approach 2: Implementing Runnable class MyRunnable implements Runnable { @Override public void run() { System.out.println("Runnable approach: " + Thread.currentThread().getName()); } } public class Main { public static void main(String[] args) { // Using Thread subclass MyThread thread1 = new MyThread(); thread1.start(); // Using Runnable Thread thread2 = new Thread(new MyRunnable()); thread2.start(); // Using lambda with Runnable Thread thread3 = new Thread(() -> System.out.println("Lambda Runnable: " + Thread.currentThread().getName())); thread3.start(); } }
此示例比较了在 Java 中创建线程的两种方法。 Runnable 方法更灵活,因为它允许您的类在需要时扩展另一个类。 它还可以更好地与现代 Java 功能(如 Lambda 和线程池)配合使用。 Thread 方法更简单,但灵活性较差,因为 Java 不支持多重继承。
来源
在本教程中,我们通过实际示例深入探讨了 Java Runnable 接口。 Runnable 是 Java 并发模型的基础,理解它对于在 Java 中编写多线程应用程序至关重要。
作者
列出所有Java教程。