Java 多线程基础
Java 多线程基础
核心概念区分
程序、进程、线程
- 程序:静止的应用程序,是指令和数据的集合。
- 进程:运行中的应用程序,是操作系统资源分配的基本单位,在内存中占据独立空间。
- 线程:进程内的独立执行单元,是 CPU 调度的基本单位。一个进程可包含多个线程,线程共享进程的资源。
多线程的优点
- 业务拆分更灵活,提升系统并发处理能力。
- 多处理器环境下可实现并行执行,单处理器环境下通过时间分片实现并发,提高资源利用率。
- 程序响应更快、交互性更强,部分场景下(如 IO 密集型任务)单处理器上也能提升执行效率。
- Java 内置完善的多线程支持,包括线程创建、运行及资源冲突控制。

在 Java 中,每个并发任务需封装为 Runnable 接口的实例(可运行对象),线程则是执行这些任务的载体。
Java 实现多线程的四种方式
方式一:实现 Runnable 接口(传统)
通过实现 Runnable 接口定义任务,再将任务传入 Thread 实例启动线程,任务与线程分离,是推荐的传统方式。
代码示例
package com.thread;
/**
* @author Jing61
*/
public class TaskThreadDemo {
public static void main(String[] args) {
// 创建线程1对象
PrintLetterTask task1 = new PrintLetterTask('A', 100);
Thread thread1 = new Thread(task1);
// 创建线程2对象
Thread thread2 = new Thread(new PrintLetterTask('B', 100));
// 创建线程3对象
Thread thread3 = new Thread(new PrintNumberTask(100));
// 启动线程(告诉操作系统,该线程已就绪,等待操作系统分配资源,由操作系统调度执行)
thread1.start();
// 启动线程
thread2.start();
// 启动线程
thread3.start();
}
}
/**
* 创建线程的方式:实现Runnable接口
* 该任务完成打印特定字母times次
*/
class PrintLetterTask implements Runnable {
private char letter;
private int times;
public PrintLetterTask(char letter, int times) {
this.letter = letter;
this.times = times;
}
@Override
public void run() {
for (int i = 0; i < times; i++) {
System.out.print(letter);
}
System.out.println();
}
}
/**
* 该任务连续打印数字
*/
class PrintNumberTask implements Runnable {
private int lastNumber;
public PrintNumberTask(int number) {
this.lastNumber = number;
}
@Override
public void run() {
for (int i = 1; i <= lastNumber; i++) {
System.out.print(i + " ");
}
System.out.println();
}
}
方式二:继承 Thread 类(传统)
Thread 类本身实现了 Runnable 接口,可通过继承 Thread 并重写 run 方法定义线程,但不推荐使用。
缺点
- 任务与线程机制耦合,不符合“单一职责”设计原则。
- 受 Java 单继承限制,无法再继承其他类。
代码示例
package com.thread;
/**
* @author Jing61
* 会出现问题——线程同步问题(会出现不同线程卖同一张票的问题),本文暂不做讲解。
* 此处仅展示如何执行
*/
public class CustomThreadClient {
public static void main(String[] args) {
// 5 个窗口卖票
for (int i = 0; i < 5; i++) {
Thread thread = new CustomThread();
thread.start();
}
}
}
/**
* 继承Thread类,覆盖run方法
*/
class CustomThread extends Thread {
private int ticket = 100;
@Override
public void run() {
while (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "正在卖出编号为" + ticket + "的票");
ticket--;
}
}
}
方式三:线程池(高效管理多任务)
对于大量任务,频繁创建销毁线程会降低效率,线程池通过复用线程、控制并发数优化性能。Java 提供 Executor 接口执行任务,ExecutorService 接口(Executor 子接口)管理任务。
线程池创建方式(Executors 静态方法)
| 方法 | 核心特性 | 适用场景 |
|---|---|---|
| newFixedThreadPool(int n) | 固定线程数,线程可重用 | 任务量稳定、需控制并发数的场景 |
| newCachedThreadPool() | 缓存线程池,无固定大小,60秒空闲线程销毁 | 大量短期小任务 |
| newSingleThreadExecutor() | 单线程池,线程异常时自动替换 | 需串行执行任务的场景 |
| newScheduledThreadPool(int corePoolSize) | 定时/延迟执行,核心线程数固定 | 定时任务、延迟任务 |
| newSingleThreadScheduledExecutor() | 单线程定时池 | 串行执行的定时/延迟任务 |
| newWorkStealingPool(int parallelism) | 支持并行级别的线程池,多队列减少竞争 | 高并行度的任务;无参版本默认以 CPU 核心数为并行度 |
代码示例
package com.thread;
import java.util.concurrent.Executors;
/**
* @author Jing61
*/
public class ExecutorDemo {
public static void main(String[] args) {
// 创建线程池 ExecutorService
// var executor = Executors.newFixedThreadPool(3); // 固定3个线程
// var executor = Executors.newCachedThreadPool(); // 缓存线程池
// 创建单线程池,线程异常时自动替换
var executor = Executors.newSingleThreadExecutor();
// 向线程池中提交任务(线程池会分配线程执行任务)
executor.execute(new PrintLetterTask('A', 10));
executor.execute(new PrintLetterTask('B', 10));
executor.execute(new PrintLetterTask('C', 10));
executor.execute(new PrintLetterTask('D', 10));
executor.execute(new PrintNumberTask(50));
// 关闭线程池(不再接受新的任务,等待所有任务执行完毕)
executor.shutdown();
System.out.println("线程池已关闭");
}
}
方式四:Callable + Future(带返回值的线程)
Callable 接口是 Runnable 的增强版,call() 方法可返回任务执行结果、抛出异常。结合 Future 接口可跟踪异步计算结果,FutureTask 是 Future 的实现类(同时实现 Runnable 接口),可作为 Thread 的目标对象或提交给线程池。
核心组件说明
- Callable:定义带返回值的任务,核心方法
call()。 - Future:管理异步结果,提供
get()(阻塞获取结果)、cancel()(取消任务)、isDone()(判断任务是否完成)等方法。 - FutureTask:包装 Callable/Runnable 对象,兼具 Runnable 和 Future 特性。
代码示例
package com.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
/**
* @author Jing61
*/
public class CallableAndFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建FutureTask,包装Callable任务(返回值类型为String)
FutureTask<String> task = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("call方法执行了");
Thread.sleep(5000); // 模拟任务执行耗时
return "hello world";
}
});
var executor = Executors.newSingleThreadExecutor();
var future = executor.submit(task);
// 获取call方法返回值(阻塞,直到任务执行完毕)
System.out.println(task.get());
System.out.println(future.isDone()); // 判断线程是否运行完毕
executor.shutdown();
}
}

浙公网安备 33010602011771号