1. 基本概念
1.1 Thread(线程)
Thread是 Java 中执行任务的载体,它代表一个操作系统线程的实例。通过继承
Thread类并重写run()方法,可以定义线程要执行的任务。缺点:继承方式导致无法再继承其他类;频繁创建和销毁线程开销大。
1.2 Runnable(可运行任务)
一个函数式接口,仅包含
void run()方法,不返回结果,也不能抛出受检异常。任务是无返回值的,适合单纯的执行操作。
可以通过
new Thread(runnable).start()或提交给线程池执行。
1.3 Callable(可调用任务)
一个函数式接口,包含
V call() throws Exception方法,可返回结果并能抛出异常。任务有返回值(通过
Future获取),更适合需要异步计算结果或处理异常的场景。通常与
ExecutorService和Future搭配使用。
1.4 线程池(Thread Pool)
一种管理和复用线程的机制,例如
ThreadPoolExecutor。避免频繁创建/销毁线程的开销,控制并发线程数量,提供任务排队、拒绝策略等能力。
核心接口是
ExecutorService,常用工厂类Executors创建。
2. 它们之间的关系
text
任务(Runnable / Callable) ---> 线程池(ExecutorService) ---> 工作线程(Thread)Runnable 和 Callable 描述“做什么”(任务逻辑)。
Thread 是“谁来做”(执行任务的实体),但现代开发中很少直接操作
Thread。线程池 则是“如何高效地安排谁来做”(任务调度 + 线程生命周期管理)。
2.1 典型组合方式
2.2 代码示例
java
// Runnable 任务
Runnable task = () -> System.out.println("Hello Runnable");
// Callable 任务
Callable<Integer> calc = () -> {
Thread.sleep(1000);
return 42;
};
// 线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
// 提交 Runnable(无返回值)
pool.execute(task);
// 提交 Callable(有返回值)
Future<Integer> future = pool.submit(calc);
Integer result = future.get(); // 阻塞获取结果
pool.shutdown();3. 核心区别总结
4. 补充:Future 与 Callable 的绑定
Callable 通常与 Future 一起工作,Future 代表异步计算的结果,提供:
get()阻塞获取结果cancel()取消任务isDone()检查是否完成
5. 实践建议
避免直接使用
Thread,除非写教学代码或极简场景。优先使用线程池 +
Runnable/Callable,充分利用复用和资源控制。需要返回值或异常处理时选
Callable,否则用Runnable。线程池推荐使用
ThreadPoolExecutor构造器(而不是Executors工厂),以便明确设置队列、拒绝策略等参数,防止资源耗尽。
package com.wss.wssdemo.config;
import lombok.Getter;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
import java.util.concurrent.*;
public class CustomThreadPool {
// 获取CPU核心数(用于调整线程数量)
private static final int CPU_CORES = Runtime.getRuntime().availableProcessors();
// 任务类型:根据实际场景调整
// - IO密集型(如网络调用、文件读写):线程数可设为 CPU_CORES * 2
// - CPU密集型(如计算):线程数设为 CPU_CORES + 1
private static final int CORE_POOL_SIZE = CPU_CORES; // 核心线程数
private static final int MAX_POOL_SIZE = CPU_CORES * 2; // 最大线程数
private static final long KEEP_ALIVE_TIME = 60L; // 空闲线程存活时间
private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS; // 时间单位
private static final int QUEUE_CAPACITY = 100; // 有界队列容量
// 创建线程池(使用CallerRunsPolicy拒绝策略)
private static final ThreadPoolExecutor THREAD_POOL = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TIME_UNIT,
new LinkedBlockingQueue<>(QUEUE_CAPACITY), // 有界队列,防止内存溢出
new ThreadPoolExecutor.CallerRunsPolicy() // 队列满且线程数达上限时,由调用者线程执行
);
@Getter
private static Scheduler scheduler = Schedulers.fromExecutor(CustomThreadPool.getThreadPool());;
/**
* 获取线程池实例
*/
public static ExecutorService getThreadPool() {
return THREAD_POOL;
}
/**
* 优雅关闭线程池(可选)
*/
public static void shutdown() {
THREAD_POOL.shutdown();
try {
if (!THREAD_POOL.awaitTermination(60, TimeUnit.SECONDS)) {
THREAD_POOL.shutdownNow();
}
} catch (InterruptedException e) {
THREAD_POOL.shutdownNow();
Thread.currentThread().interrupt();
}
}
}