文章目录
Java 多线程编程:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口
在 Java 中,多线程编程是实现并发任务的重要手段。Java 提供了多种创建线程的方式,其中最常用的三种方式是:
- 继承
Thread
类。 - 实现
Runnable
接口。 - 实现
Callable
接口。
本文将详细介绍这三种方式的使用方法、优缺点以及适用场景,并通过代码示例帮助你更好地理解。
1. 继承 Thread
类
1.1 使用方法
通过继承 Thread
类并重写 run()
方法,可以创建一个线程类。然后通过调用 start()
方法启动线程。
1.2 代码示例
public class MyThread extends Thread {
@Override
public void run() {
// 线程执行的任务
System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");
}
public static void main(String[] args) {
// 创建线程对象
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
// 启动线程
thread1.start();
thread2.start();
}
}
1.3 输出
线程 Thread-0 正在运行
线程 Thread-1 正在运行
1.4 优缺点
- 优点:
- 简单易用,适合快速实现线程。
- 缺点:
- Java 是单继承的,继承
Thread
类后无法再继承其他类。 - 代码耦合性较高,任务逻辑与线程类绑定。
- Java 是单继承的,继承
2. 实现 Runnable
接口
2.1 使用方法
通过实现 Runnable
接口并实现 run()
方法,可以将任务逻辑与线程分离。然后通过 Thread
类启动线程。
2.2 代码示例
public class MyRunnable implements Runnable {
@Override
public void run() {
// 线程执行的任务
System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");
}
public static void main(String[] args) {
// 创建任务对象
MyRunnable task = new MyRunnable();
// 创建线程对象并启动
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
}
}
2.3 输出
线程 Thread-0 正在运行
线程 Thread-1 正在运行
2.4 优缺点
- 优点:
- 任务逻辑与线程解耦,代码更灵活。
- 可以避免单继承的限制。
- 缺点:
- 无法直接获取线程执行的结果。
3. 实现 Callable
接口
3.1 使用方法
Callable
接口与 Runnable
接口类似,但 Callable
的 call()
方法可以返回结果,并且可以抛出异常。通常与 ExecutorService
和 Future
结合使用。
3.2 代码示例
import java.util.concurrent.*;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
// 线程执行的任务
return "线程 " + Thread.currentThread().getName() + " 执行完成";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 提交任务
Future<String> future1 = executorService.submit(new MyCallable());
Future<String> future2 = executorService.submit(new MyCallable());
// 获取任务结果
System.out.println(future1.get());
System.out.println(future2.get());
// 关闭线程池
executorService.shutdown();
}
}
3.3 输出
线程 pool-1-thread-1 执行完成
线程 pool-1-thread-2 执行完成
3.4 优缺点
- 优点:
- 可以获取线程执行的结果。
- 支持抛出异常。
- 缺点:
- 使用稍复杂,需要结合
ExecutorService
和Future
。
- 使用稍复杂,需要结合
4. 三种方式的对比
特性 | 继承 Thread 类 | 实现 Runnable 接口 | 实现 Callable 接口 |
---|---|---|---|
任务与线程耦合 | 高 | 低 | 低 |
返回值 | 不支持 | 不支持 | 支持 |
异常处理 | 不支持 | 不支持 | 支持 |
适用场景 | 简单任务 | 解耦任务 | 需要返回结果的任务 |
5. 如何选择?
- 继承
Thread
类:- 适合简单的任务,且不需要继承其他类。
- 实现
Runnable
接口:- 适合任务与线程解耦的场景,推荐使用。
- 实现
Callable
接口:- 适合需要返回结果或抛出异常的任务。
6. 总结
Java 提供了多种创建线程的方式,每种方式都有其适用场景:
- 继承
Thread
类简单易用,但耦合性高。 - 实现
Runnable
接口灵活解耦,推荐使用。 - 实现
Callable
接口支持返回结果和异常处理,适合复杂任务。
通过合理选择线程创建方式,可以编写出高效、灵活的多线程程序。希望本文能帮助你更好地理解和使用 Java 多线程编程!如果有任何问题,欢迎留言讨论!
7.其他
void contextLoads14() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 执行完成");
}
});
Future<String> future1 = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return "线程 " + Thread.currentThread().getName() + " 执行完成";
}
});
// 获取任务结果
System.out.println(future1.get());
// 关闭线程池
executorService.shutdown();
}