线程创建方式
四种方式,适用场景各不同。
方式总览
| 方式 | 实现 | 返回值 | 异常处理 | 推荐场景 |
|---|---|---|---|---|
| 继承 Thread | extends Thread | void | 不能抛受检异常 | 简单场景(不推荐) |
| 实现 Runnable | implements Runnable | void | 不能抛受检异常 | 通用场景 |
| 实现 Callable | implements Callable | V | 可以抛受检异常 | 需要返回值的场景 |
| 线程池 | Executors/ThreadPoolExecutor | Future/Void | 按需处理 | 生产环境(强烈推荐) |
方式一:继承 Thread
最直接的方式,但不推荐:
java
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行中: " + Thread.currentThread().getName());
}
}
// 使用
MyThread thread = new MyThread();
thread.start(); // 记住是 start(),不是 run()为什么说不推荐?
java
// 问题一:Java 单继承限制
class MyClass extends Parent { } // 只能继承一个类
// 如果用 Thread,就没法再继承其他类了
// 问题二:任务和线程耦合
// MyThread 既包含任务逻辑,又包含线程管理
// 不能把同一个任务交给多个线程执行start() vs run()
java
Thread thread = new Thread(() -> System.out.println("线程运行"));
thread.start(); // ✅ 启动新线程,异步执行
thread.run(); // ❌ 只是普通方法调用,同步执行方式二:实现 Runnable
推荐的基本方式:
java
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程执行中: " + Thread.currentThread().getName());
}
}
// 使用
Thread thread = new Thread(new MyRunnable());
thread.start();优点:
- 解决单继承问题
- 任务和线程解耦
- 可以共享同一个 Runnable 实例
java
// 同一个任务,多个线程执行
class ShareTask implements Runnable {
private int count = 0;
@Override
public void run() {
count++;
System.out.println(Thread.currentThread().getName() + " - count: " + count);
}
}
ShareTask task = new ShareTask();
new Thread(task, "A").start(); // A - count: 1
new Thread(task, "B").start(); // B - count: 2
new Thread(task, "C").start(); // C - count: 3Lambda 简化(JDK 8+)
java
// 完整写法
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
});
// Lambda 简化(JDK 8+)
Thread thread2 = new Thread(() -> System.out.println("Hello"));方式三:实现 Callable
Runnable 的问题是不能返回结果,Callable 解决了这个问题:
java
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
return sum; // 可以返回结果
}
}
// 使用
MyCallable callable = new MyCallable();
FutureTask<Integer> future = new FutureTask<>(callable);
Thread thread = new Thread(future);
thread.start();
// 获取结果(会阻塞直到结果返回)
try {
Integer result = future.get(); // 5050
System.out.println("计算结果: " + result);
} catch (Exception e) {
e.printStackTrace();
}Callable vs Runnable
| 对比项 | Runnable | Callable |
|---|---|---|
| 返回值 | void | V |
| 异常 | 不能抛出受检异常 | 可以抛出受检异常 |
| 使用方式 | Thread / ExecutorService.execute() | ExecutorService.submit() |
| 配套类 | 无 | FutureTask |
FutureTask 的额外能力
java
FutureTask<Integer> future = new FutureTask<>(() -> {
// 模拟耗时操作
Thread.sleep(2000);
return 42;
});
new Thread(future).start();
System.out.println("任务是否完成: " + future.isDone());
// 带超时的获取
Integer result = future.get(5, TimeUnit.SECONDS); // 等 5 秒
System.out.println("结果: " + result);
// 取消任务
future.cancel(true); // true = 可以中断正在执行的任务方式四:线程池(生产环境推荐)
线程创建和销毁有开销,线程池复用线程,避免频繁创建销毁:
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// 常见线程池类型
ExecutorService cachedPool = Executors.newCachedThreadPool(); // 动态线程数
ExecutorService singlePool = Executors.newSingleThreadExecutor(); // 单线程
ExecutorService fixedPool = Executors.newFixedThreadPool(5); // 固定线程数
// 提交任务
fixedPool.submit(() -> System.out.println("任务1"));
fixedPool.submit(() -> System.out.println("任务2"));
fixedPool.submit(() -> System.out.println("任务3"));
// 关闭线程池
fixedPool.shutdown(); // 不再接受新任务,等待已提交任务完成
fixedPool.shutdownNow(); // 尝试停止所有任务
// 带返回值的提交
Future<Integer> future = fixedPool.submit(() -> {
Thread.sleep(1000);
return 42;
});
Integer result = future.get(); // 阻塞等待结果为什么不推荐 Executors 工厂方法?
java
// 问题:Executors 创建的线程池可能有风险
// FixedThreadPool 和 SingleThreadExecutor 使用无界队列,可能 OOM
ExecutorService executor = Executors.newFixedThreadPool(2);
// 任务太多,队列无限增长,内存爆炸
// 推荐:手动创建线程池,明确参数
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new ArrayBlockingQueue<>(10), // 有界队列,防止 OOM
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);对比总结
简单场景
java
// 临时任务,不复用,直接用 Lambda
Thread t = new Thread(() -> {
System.out.println("一次性任务");
});
t.start();需要结果
java
// 用线程池 + Callable
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<Integer> future = executor.submit(() -> {
return calculateSum();
});
Integer result = future.get();生产环境
java
// 自定义线程池,参数可控
ThreadPoolExecutor executor = new ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors(), // CPU 核心数
Runtime.getRuntime().availableProcessors() * 2, // 最大线程数
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new ThreadPoolExecutor.CallerRunsPolicy()
);Java 21+ 虚拟线程
java
// 大量 I/O 任务,用虚拟线程
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i ->
executor.submit(() -> {
// 模拟 I/O
Thread.sleep(Duration.ofSeconds(1));
})
);
}Thread 类常用方法
java
Thread thread = new Thread(() -> {
System.out.println("执行中");
}, "MyThread");
// 设置
thread.setName("MyThread");
thread.setPriority(Thread.MAX_PRIORITY); // 1-10
thread.setDaemon(true); // 守护线程
// 获取
thread.getId(); // 线程 ID
thread.getName(); // 线程名称
thread.getPriority(); // 优先级
thread.getState(); // 线程状态
thread.isAlive(); // 是否存活
thread.isDaemon(); // 是否守护线程
thread.isInterrupted(); // 是否被中断
// 控制
thread.start(); // 启动
thread.join(); // 等待结束
thread.join(1000); // 等待超时(1秒)
thread.sleep(1000); // 休眠(不释放锁)
thread.interrupt(); // 中断
Thread.yield(); // 礼让(建议调度器切换)总结
- 简单临时任务:直接
new Thread(() -> {...}) - 通用场景:用 Runnable + 线程池
- 需要返回值:用 Callable + Future + 线程池
- 生产环境:自定义 ThreadPoolExecutor
- 大量 I/O 任务:用虚拟线程(Java 21+)
记住:start() 启动线程,run() 只是普通方法调用。
