Java 中实现多线程主要有 4 种常见方式,从简单到灵活依次是:继承 Thread、实现 Runnable、实现 Callable(可返回结果)、以及使用线程池。下面用代码案例逐一说明。

一、继承 Thread 类(简单但不推荐)
java
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 运行中");
}
public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
}
}缺点:单继承限制,任务与线程耦合。
二、实现 Runnable 接口(推荐解耦)
java
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 执行Runnable");
}
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
Thread t2 = new Thread(new MyRunnable());
t1.start();
t2.start();
}
}Lambda 简化(Java 8+):
java
Thread t = new Thread(() -> System.out.println("Lambda线程"));
t.start();三、实现 Callable + FutureTask(带返回值)
java
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return Thread.currentThread().getName() +"任务结果";
}
public static void main(String[] args) throws Exception {
FutureTask<String> task1 = new FutureTask<>(new MyCallable());
FutureTask<String> task2 = new FutureTask<>(new MyCallable());
new Thread(task1).start();
new Thread(task2).start();
System.out.println(task1.get()); // 阻塞获取结果
System.out.println(task2.get()); // 阻塞获取结果
}
}四、线程池(核心:使用 ThreadPoolExecutor)
❌ 不推荐:Executors 的隐患示例
java
// 危险:无界队列,任务多时 OOM
ExecutorService pool = Executors.newFixedThreadPool(10);
for (int i = 0; i < Integer.MAX_VALUE; i++) {
pool.submit(() -> {
Thread.sleep(1000);
});
}✅ 推荐:ThreadPoolExecutor 自定义参数
java
import java.util.concurrent.*;
public class SafeThreadPool {
public static void main(String[] args) {
// 核心线程数 = 2,最大线程数 = 5,空闲存活时间 = 60秒
// 阻塞队列 = 有界队列 ArrayBlockingQueue 容量 10
// 拒绝策略 = CallerRunsPolicy(让提交任务的线程自己执行)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // corePoolSize
5, // maximumPoolSize
60L, // keepAliveTime
TimeUnit.SECONDS, // 时间单位
new ArrayBlockingQueue<>(10), // 有界队列,避免内存爆炸
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
// 提交任务
for (int i = 1; i <= 20; i++) {
final int taskId = i;
executor.execute(() -> {
System.out.println(Thread.currentThread().getName() + " 执行任务 " + taskId);
try { Thread.sleep(100); } catch (InterruptedException e) {}
});
}
executor.shutdown();
}
}关键参数说明
常用拒绝策略
AbortPolicy:直接抛RejectedExecutionException(默认)CallerRunsPolicy:由提交任务的线程自己执行,降低提交速度DiscardPolicy:静默丢弃DiscardOldestPolicy:丢弃队列中最老的任务
有界队列示例(防止内存爆炸)
java
// 有界队列,容量 100
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);
// 或者用 LinkedBlockingQueue 指定容量
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(100);五、CompletableFuture(异步编排,推荐现代用法)
内部使用 ForkJoinPool.commonPool(),生产环境建议自定义线程池(也是 ThreadPoolExecutor)。
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
public class CompletableFutureDemo {
public static void main(String[] args) {
// 自定义线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(50)
);
CompletableFuture.supplyAsync(() -> "Hello", executor)
.thenApply(s -> s + " World")
.thenAccept(System.out::println);
executor.shutdown();
}
}CompletableFuture 就是“异步任务的流水线工具”:你可以提交一个任务,然后像搭积木一样串接后续步骤、组合多个并行任务,并且全程不阻塞当前线程。
总结对比(含安全建议)
一句话:永远不要在正式项目中使用 Executors.newFixedThreadPool() / newCachedThreadPool(),一律用 ThreadPoolExecutor 构造方法,并指定有界队列 + 合理拒绝策略。