Java 创建线程的几种方式
在 Java 中,创建线程主要有以下几种方式。下面我将详细解释每种方式,并提供代码示例。
1. 继承 Thread 类
这是最基础的创建线程方式,通过继承 Thread
类并重写 run()
方法。
public class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程运行中: " + Thread.currentThread().getName());}
}// 使用方式
public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start(); // 启动线程}
}
特点:
- 简单直接
- 由于 Java 是单继承,这种方式会占用继承位置
- 线程与任务耦合在一起
2. 实现 Runnable 接口
更常用的方式是实现 Runnable
接口,将线程和任务解耦。
public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程运行中: " + Thread.currentThread().getName());}
}// 使用方式
public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();// 或者使用 Lambda 表达式(Java 8+)Thread lambdaThread = new Thread(() -> {System.out.println("Lambda 线程运行中: " + Thread.currentThread().getName());});lambdaThread.start();}
}
特点:
- 推荐使用的方式
- 线程与任务分离,更灵活
- 可以实现多个接口,不影响类继承结构
3. 实现 Callable 接口
Callable
与 Runnable
类似,但可以返回结果和抛出异常。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;public class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {Thread.sleep(1000); // 模拟耗时操作return "任务执行完成: " + Thread.currentThread().getName();}
}// 使用方式
public class Main {public static void main(String[] args) throws Exception {FutureTask<String> futureTask = new FutureTask<>(new MyCallable());Thread thread = new Thread(futureTask);thread.start();// 获取执行结果(会阻塞直到任务完成)String result = futureTask.get();System.out.println(result);}
}
特点:
- 可以返回执行结果
- 可以抛出异常
- 需要配合
FutureTask
或线程池使用
4. 使用线程池(ExecutorService)
在实际开发中,最推荐使用线程池来管理线程,提高资源利用率。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class ThreadPoolExample {public static void main(String[] args) {// 创建固定大小的线程池ExecutorService executor = Executors.newFixedThreadPool(3);// 提交任务for (int i = 0; i < 5; i++) {final int taskId = i;executor.submit(() -> {System.out.println("任务 " + taskId + " 执行中: " + Thread.currentThread().getName());try {TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();try {// 等待所有任务完成if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {executor.shutdownNow();}} catch (InterruptedException e) {executor.shutdownNow();}}
}
特点:
- 管理和复用线程,减少创建销毁开销
- 控制并发线程数量
- 提供任务队列、定时执行等功能
5. 使用 CompletableFuture (Java 8+)
Java 8 引入的 CompletableFuture
提供了更强大的异步编程能力。
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;public class CompletableFutureExample {public static void main(String[] args) throws ExecutionException, InterruptedException {// 创建异步任务CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return "异步任务结果";});// 处理任务结果future.thenAccept(result -> {System.out.println("处理结果: " + result);});// 等待任务完成future.get();}
}
6. 使用 Spring 的 @Async 注解
在 Spring 框架中,可以使用 @Async
注解轻松创建异步方法。
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;@EnableAsync
@Component
public class AsyncService {@Asyncpublic void asyncMethod() {System.out.println("异步方法执行: " + Thread.currentThread().getName());}
}// 在 Controller 或 Service 中调用
asyncService.asyncMethod();
对比总结
创建方式 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
继承 Thread | 简单直接 | 占用继承位置,耦合度高 | 简单测试或demo |
实现 Runnable | 灵活,解耦 | 不能直接返回结果 | 大多数场景 |
实现 Callable | 可返回结果,可抛异常 | 使用稍复杂 | 需要返回结果的异步任务 |
线程池 | 资源复用,功能强大 | 配置稍复杂 | 生产环境,高并发场景 |
CompletableFuture | 功能强大,链式编程 | Java 8+ 支持 | 复杂异步编程 |
Spring @Async | 集成简单,注解驱动 | 需要 Spring 环境 | Spring 项目中的异步处理 |
最佳实践建议
- 优先使用线程池而不是直接创建线程,避免资源浪费
- 实现 Runnable 接口比继承 Thread 类更灵活
- 需要返回值时使用 Callable 和 Future
- 在 Spring 项目中使用 @Async 注解简化异步编程
- 对于复杂异步流程,使用 CompletableFuture
- 始终处理线程中的异常,避免 silent failure
// 异常处理示例
Thread thread = new Thread(() -> {try {// 任务代码} catch (Exception e) {System.err.println("线程执行异常: " + e.getMessage());}
});
thread.setUncaughtExceptionHandler((t, e) -> {System.err.println("线程 " + t.getName() + " 发生异常: " + e.getMessage());
});
thread.start();
根据具体需求选择合适的线程创建方式,可以提高代码的可维护性和性能。