JDK8 中线程实现方法与底层逻辑深度解析
作者:乐观甜甜圈
JDK8提供了多种线程实现方式,包括继承Thread类、实现Runnable接口和Callable接口,还介绍了线程池的实现和JDK8新增特性CompletableFuture,底层线程模型包括JVM线程与操作系统线程的关系、线程状态转换以及创建与销毁的开销,感兴趣的朋友跟随小编一起看看吧
一、引言
在 Java 并发编程中,线程是最基础的执行单元。JDK8 提供了多种创建和管理线程的方式,每种方式都有其特定的使用场景和底层实现机制。本文将全面解析 JDK8 中实现线程的方法及其底层逻辑。
二、线程实现的三种核心方式
1. 继承 Thread 类
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行: " + Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
}底层逻辑:
- Thread 类本身实现了 Runnable 接口
- JVM 调用
start()方法后,会在底层创建真正的操作系统线程 start()方法通过 JNI(Java Native Interface)调用操作系统原生线程创建 API- 线程创建完成后,JVM 调度执行
run()方法
2. 实现 Runnable 接口(推荐方式)
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable执行: " + Thread.currentThread().getName());
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}底层逻辑:
- Runnable 是函数式接口,只定义
run()方法 - Thread 类接收 Runnable 实例作为执行目标
- 避免了 Java 单继承的限制,更加灵活
- 符合面向对象设计原则:组合优于继承
3. 实现 Callable 接口
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "Callable执行结果: " + Thread.currentThread().getName();
}
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new MyCallable());
System.out.println(future.get()); // 获取返回值
executor.shutdown();
}
}底层逻辑:
- Callable 允许返回结果和抛出异常
- 通过 FutureTask 包装,实现 RunnableFuture 接口
- ExecutorService 提交任务时,内部创建 FutureTask
- 任务执行结果通过 Future 对象获取,支持异步编程模型
三、线程池的实现(Executor Framework)
核心线程池类型
// 1. 固定大小线程池 ExecutorService fixedPool = Executors.newFixedThreadPool(5); // 2. 缓存线程池 ExecutorService cachedPool = Executors.newCachedThreadPool(); // 3. 单线程池 ExecutorService singlePool = Executors.newSingleThreadExecutor(); // 4. 调度线程池 ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(3);
ThreadPoolExecutor 核心原理
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 工作队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)工作流程示意图:
提交任务 → 核心线程是否满? → 否 → 创建核心线程执行
↓是
工作队列是否满? → 否 → 加入队列等待
↓是
最大线程是否满? → 否 → 创建临时线程
↓是
执行拒绝策略底层数据结构:
- Worker 内部类:包装线程和任务
- BlockingQueue:存储待执行任务(ArrayBlockingQueue、LinkedBlockingQueue 等)
- AtomicInteger:使用 CAS 操作维护线程池状态和线程数
四、JDK8 新增特性:CompletableFuture
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("异步执行: " + Thread.currentThread().getName());
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
return "异步计算结果";
});底层逻辑:
- 基于 ForkJoinPool.commonPool() 或自定义线程池
- 实现 CompletionStage 接口,支持流式编程
- 内部使用 Completion 链表管理依赖关系
- 提供丰富的组合操作(thenApply、thenAccept、thenCombine 等)
五、底层线程模型详解
1. JVM 线程与操作系统线程关系
Java Thread → JVM Thread → pthread(Linux)/ Windows Thread → CPU 调度
- 1:1 模型:每个 Java 线程对应一个操作系统原生线程
- 绿色线程(Green Threads):早期 JVM 使用的用户态线程,已弃用
- 线程栈:每个线程拥有独立的栈空间(默认 1MB,可通过
-Xss调整)
2. 线程状态转换
public enum State {
NEW, // 新建
RUNNABLE, // 可运行(包括就绪和运行)
BLOCKED, // 阻塞(等待监视器锁)
WAITING, // 等待(无限期等待)
TIMED_WAITING, // 超时等待
TERMINATED // 终止
}状态转换图:
NEW --start()--> RUNNABLE RUNNABLE --获取锁失败--> BLOCKED RUNNABLE --wait()/join()--> WAITING RUNNABLE --sleep(n)/wait(n)--> TIMED_WAITING 各种状态 --执行完毕/异常--> TERMINATED
3. 线程创建与销毁开销
创建开销:
- 分配线程栈内存(1MB 默认)
- 系统调用创建原生线程
- 初始化线程本地存储(ThreadLocal)
优化建议:
- 使用线程池复用线程
- 合理设置线程栈大小
- 避免频繁创建销毁线程
到此这篇关于JDK8 中线程实现方法与底层逻辑深度解析的文章就介绍到这了,更多相关jdk线程实现方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
