2026-11-09 08:42:34Java 多线程实现方式(原理+实战+对比)

我会从基础实现到进阶用法,系统讲解Java多线程的所有核心实现方式,包括每种方式的原理、代码示例、适用场景和优缺点,新手也能快速上手。

一、核心实现方式(官方标准+实际常用)

Java中多线程的实现本质只有两种核心方式(Java官方定义),但实际开发中衍生出3种常用形式,先明确分类:

实现类型

核心原理

JDK版本

核心特点

继承Thread类

重写run()方法,线程执行体

1.0+

简单,单继承限制

实现Runnable接口

重写run(),解耦任务与线程

1.0+

无单继承限制,推荐

实现Callable+FutureTask

有返回值、可抛异常的Runnable

1.5+

能获取执行结果,处理异常

线程池(Executor框架)

复用线程,管理任务执行

1.5+

高性能,可控,生产首选

定时器(Timer/TimerTask)

定时/周期性执行任务

1.3+

简单定时任务,单线程

二、方式1:继承Thread类(基础)

原理

Thread类是Java线程的核心类,继承它并重写run()方法(线程执行体),调用start()方法启动线程(JVM会调用run())。

代码示例

// 1. 继承Thread类

class MyThread extends Thread {

// 重写run():线程要执行的任务

@Override

public void run() {

for (int i = 0; i < 5; i++) {

// Thread.currentThread().getName() 获取当前线程名

System.out.println(Thread.currentThread().getName() + " 执行:" + i);

try {

Thread.sleep(100); // 模拟耗时操作

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public class ThreadDemo {

public static void main(String[] args) {

// 2. 创建线程实例

MyThread thread1 = new MyThread();

MyThread thread2 = new MyThread();

// 3. 设置线程名(可选)

thread1.setName("线程1");

thread2.setName("线程2");

// 4. 启动线程(必须调用start(),而非直接run())

thread1.start();

thread2.start();

// 注意:直接调用run()会以主线程执行,不是多线程!

// thread1.run(); // 错误用法

}

}

输出结果(示例)

线程1 执行:0

线程2 执行:0

线程1 执行:1

线程2 执行:1

...

优缺点

✅ 优点:代码简单,直接操作线程对象;

❌ 缺点:Java单继承限制,任务与线程耦合(无法复用任务)。

三、方式2:实现Runnable接口(推荐基础方式)

原理

将“任务逻辑”与“线程对象”解耦:Runnable封装任务(重写run()),Thread负责执行任务(传入Runnable实例)。

代码示例

// 1. 实现Runnable接口,封装任务

class MyRunnable implements Runnable {

@Override

public void run() {

for (int i = 0; i < 5; i++) {

System.out.println(Thread.currentThread().getName() + " 执行:" + i);

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public class RunnableDemo {

public static void main(String[] args) {

// 2. 创建任务实例

MyRunnable task = new MyRunnable();

// 3. 创建线程,传入任务

Thread thread1 = new Thread(task, "线程1");

Thread thread2 = new Thread(task, "线程2");

// 4. 启动线程

thread1.start();

thread2.start();

}

}

进阶:匿名内部类/Lambda简化(JDK8+)

public class RunnableLambdaDemo {

public static void main(String[] args) {

// Lambda表达式简化Runnable(无需定义类)

Runnable task = () -> {

for (int i = 0; i < 5; i++) {

System.out.println(Thread.currentThread().getName() + " 执行:" + i);

try { Thread.sleep(100); } catch (InterruptedException e) {}

}

};

new Thread(task, "Lambda线程1").start();

new Thread(task, "Lambda线程2").start();

}

}

优缺点

✅ 优点:无单继承限制,任务与线程解耦(可复用任务);

❌ 缺点:run()无返回值,无法抛出检查异常(只能捕获)。

四、方式3:实现Callable+FutureTask(有返回值)

原理

Callable是Runnable的增强版:

call()方法有返回值(泛型);

call()可抛出检查异常;

FutureTask封装Callable,获取执行结果(get())。

代码示例

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.FutureTask;

// 1. 实现Callable接口,指定返回值类型

class MyCallable implements Callable {

private int num;

public MyCallable(int num) {

this.num = num;

}

// 有返回值、可抛异常的任务

@Override

public Integer call() throws Exception {

int sum = 0;

for (int i = 1; i <= num; i++) {

sum += i;

System.out.println(Thread.currentThread().getName() + " 计算:" + i);

Thread.sleep(100);

}

return sum; // 返回计算结果

}

}

public class CallableDemo {

public static void main(String[] args) {

// 2. 创建Callable任务

Callable callable = new MyCallable(5);

// 3. FutureTask封装Callable(既是Runnable,又是Future)

FutureTask futureTask = new FutureTask<>(callable);

// 4. 启动线程

Thread thread = new Thread(futureTask, "计算线程");

thread.start();

// 5. 获取任务结果(get()会阻塞,直到任务完成)

try {

Integer result = futureTask.get();

System.out.println("计算结果:" + result); // 输出15

} catch (InterruptedException | ExecutionException e) {

e.printStackTrace();

}

}

}

核心方法说明

futureTask.get():阻塞获取返回值;

futureTask.cancel(boolean mayInterruptIfRunning):取消任务;

futureTask.isDone():判断任务是否完成。

优缺点

✅ 优点:有返回值、可处理异常;

❌ 缺点:get()方法会阻塞,需合理处理超时。

五、方式4:线程池(Executor框架)(生产首选)

原理

线程池复用线程(避免频繁创建/销毁线程的开销),管理任务队列,控制并发数,是生产环境的最优选择。

核心线程池类型(JDK提供)

线程池类型

核心特点

适用场景

FixedThreadPool

固定核心线程数,无最大线程数

稳定的并发任务

CachedThreadPool

核心线程0,最大线程无限

短期、高频小任务

SingleThreadExecutor

单线程执行

顺序执行任务

ScheduledThreadPool

定时/周期性执行

定时任务、延迟任务

代码示例:固定线程池

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class ThreadPoolDemo {

public static void main(String[] args) {

// 1. 创建固定线程池(核心线程数=2)

ExecutorService executor = Executors.newFixedThreadPool(2);

// 2. 提交任务(Runnable)

for (int i = 0; i < 5; i++) {

int taskNum = i;

executor.submit(() -> {

System.out.println(Thread.currentThread().getName() + " 执行任务" + taskNum);

try { Thread.sleep(200); } catch (InterruptedException e) {}

});

}

// 3. 提交Callable任务(有返回值)

executor.submit(() -> {

int sum = 0;

for (int i = 1; i <= 3; i++) sum += i;

System.out.println("Callable任务结果:" + sum);

return sum;

});

// 4. 关闭线程池(生产中建议优雅关闭)

executor.shutdown(); // 等待所有任务完成后关闭

// executor.shutdownNow(); // 立即关闭,中断正在执行的任务

}

}

进阶:自定义线程池(推荐生产使用)

import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.ThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

public class CustomThreadPoolDemo {

public static void main(String[] args) {

// 自定义线程池参数(核心池大小、最大池大小、空闲时间、队列、拒绝策略)

ThreadPoolExecutor executor = new ThreadPoolExecutor(

2, // 核心线程数

4, // 最大线程数

60, // 空闲线程存活时间

TimeUnit.SECONDS, // 时间单位

new ArrayBlockingQueue<>(2), // 任务队列(容量2)

new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略(主线程执行)

);

// 提交任务

for (int i = 0; i < 7; i++) {

int taskNum = i;

executor.execute(() -> {

System.out.println(Thread.currentThread().getName() + " 执行任务" + taskNum);

try { Thread.sleep(100); } catch (InterruptedException e) {}

});

}

executor.shutdown();

}

}

优缺点

✅ 优点:复用线程、控制并发、管理任务、高性能;

❌ 缺点:需合理配置参数(核心数、队列、拒绝策略)。

六、方式5:定时器(Timer/TimerTask)(定时任务)

原理

Timer是Java早期的定时任务工具,单线程执行TimerTask(实现Runnable),支持延迟/周期性执行。

代码示例

import java.util.Timer;

import java.util.TimerTask;

public class TimerDemo {

public static void main(String[] args) {

Timer timer = new Timer("定时任务线程");

// 延迟1秒执行,每2秒重复执行

timer.schedule(new TimerTask() {

@Override

public void run() {

System.out.println(Thread.currentThread().getName() + " 执行定时任务:" + System.currentTimeMillis());

}

}, 1000, 2000);

// 5秒后取消定时器

try {

Thread.sleep(5000);

timer.cancel();

System.out.println("定时器已取消");

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

注意事项

❌ Timer是单线程,一个任务异常会导致所有任务终止;

✅ 生产中推荐用ScheduledThreadPoolExecutor替代Timer。

七、核心对比与选型建议

实现方式

返回值

异常处理

单继承限制

性能

适用场景

继承Thread

无

只能捕获

有

一般

简单demo,不推荐生产

实现Runnable

无

只能捕获

无

较好

无返回值的普通任务

Callable+FutureTask

有

可抛出

无

较好

需返回值/处理异常的任务

线程池

可选

可处理

无

最优

生产环境所有场景(推荐)

Timer/TimerTask

无

只能捕获

无

较差

简单定时任务(替代:ScheduledThreadPool)

选型核心原则

生产环境优先用线程池(性能、可控性最优);

需返回值用Callable + 线程池;

简单demo可用Runnable/Thread;

定时任务用ScheduledThreadPoolExecutor,而非Timer。

总结

Java多线程核心实现是「继承Thread」和「实现Runnable」,其余是衍生增强;

「Callable+FutureTask」解决返回值/异常问题,「线程池」解决性能/管理问题;

生产环境首选线程池(自定义参数更可控),避免直接创建Thread;

核心区别:返回值、异常处理、线程复用,选型需结合业务场景。

↑