JUC多线程核心知识点深度解析

 最近正在复习Java八股,所以会将一些热门的八股问题,结合ai与自身理解写成博客便于记忆

本文将从以上10个经典面试问题来做juc多线程的解析

一、线程状态与流转机制

1. 六种线程状态(Java定义)

public enum State {
    NEW,           // 新建未启动
    RUNNABLE,      // 可运行(包含就绪和运行中)
    BLOCKED,       // 被阻塞(等待监视器锁)
    WAITING,       // 无限期等待(无时限的wait/join/park)
    TIMED_WAITING, // 限期等待(带时限的sleep/wait/join/park)
    TERMINATED     // 终止
}

2.关键转换场景:

start():NEW → RUNNABLE
获取锁失败:RUNNABLE → BLOCKED
Object.wait():RUNNABLE → WAITING
Thread.sleep(ms)`:RUNNABLE → TIMED_WAITING
任务结束/异常:RUNNABLE → TERMINATED

二、线程创建方式对比

1. 基础创建方式

// 方式1:继承Thread类
class MyThread extends Thread {
    public void run() {
        System.out.println("Thread running");
    }
}
new MyThread().start();

// 方式2:实现Runnable接口
new Thread(() -> System.out.println("Runnable running")).start();

// 方式3:实现Callable接口(可获取返回值)
FutureTask<String> task = new FutureTask<>(() -> "Callable result");
new Thread(task).start();
String result = task.get();

2. 生产环境推荐

线程池创建(推荐所有场景)
CompletableFuture(Java8+异步编程)
虚拟线程(Java19+轻量级线程)

三、多线程典型应用场景

1. 高并发处理

电商秒杀系统
即时通讯消息推送
金融交易订单处理

2. 异步任务

```java
// 异步日志记录
executor.execute(() -> logService.saveLog(logEntity));

// 并行计算
List<Future<Result>> futures = IntStream.range(0, 10)
    .mapToObj(i -> executor.submit(() -> compute(i)))
    .collect(Collectors.toList());
```

3. 定时调度

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
scheduler.scheduleAtFixedRate(() -> {
    System.out.println("定时任务执行");
}, 1, 5, TimeUnit.SECONDS);

四、线程池核心机制

1. 七大构造参数

public ThreadPoolExecutor(
    int corePoolSize,      // 核心线程数
    int maximumPoolSize,   // 最大线程数
    long keepAliveTime,    // 空闲线程存活时间
    TimeUnit unit,         // 时间单位
    BlockingQueue<Runnable> workQueue, // 工作队列
    ThreadFactory threadFactory,       // 线程工厂
    RejectedExecutionHandler handler   // 拒绝策略
)

2. 执行流程图示


         提交任务
             │
             ▼
核心线程是否已满?──否─► 创建核心线程执行
             │是
             ▼
工作队列是否已满?──否─► 加入队列等待
             │是
             ▼
最大线程是否已满?──否─► 创建临时线程执行
             │是
             ▼
        执行拒绝策略

3. 拒绝策略对比

策略类行为适用场景
AbortPolicy(默认)抛出RejectedExecutionException需要感知任务拒绝的场景 
CallerRunsPolicy由提交线程直接执行任务不希望丢失任务的场景 
DiscardPolicy静默丢弃任务可容忍任务丢失的场景 
DiscardOldestPolicy丢弃队列最老任务并重试允许丢弃旧任务的场景       

五、线程池配置实践

1. 线程数设置公式

CPU密集型:corePoolSize = CPU核数 + 1
IO密集型:corePoolSize = CPU核数 × (1 + 平均等待时间/平均计算时间)

int cpuCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    cpuCores * 2,      // 核心线程数
    cpuCores * 4,      // 最大线程数
    60,                // 空闲线程存活时间(s)
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(1000), // 有界队列
    new NamedThreadFactory("app-thread"), // 自定义线程命名
    new CallerRunsPolicy()          // 降级策略
);

2. 避免使用Executors

问题案例:

// 可能导致OOM(无界队列)
ExecutorService executor = Executors.newFixedThreadPool(10);

// 最大线程数过大(Integer.MAX_VALUE)
ExecutorService executor = Executors.newCachedThreadPool();

六、生产环境监控指标

1. 关键监控项

指标监控方式健康标准
活跃线程数getActiveCount()≤ maximumPoolSize
任务队列大小getQueue().size()≤ 队列容量80%
已完成任务数getCompletedTaskCount()持续增长
拒绝任务数自定义RejectedExecutionHandler=0(理想情况)
线程空闲率(poolSize-activeCount)/poolSize20%~80%波动

七、常见问题解答

1:线程池为什么先填满队列再创建线程?

设计考量:
1. 线程创建销毁有开销
2. 任务排队通常比新建线程更高效
3. 避免线程数剧烈波动

2:如何选择工作队列?

选型指南:
ArrayBlockingQueue:固定大小,内存控制严格
LinkedBlockingQueue:无界/有界,吞吐量高
SynchronousQueue:直接传递,避免排队
PriorityBlockingQueue:优先级任务

3:核心线程为什么不会被回收?

设计意图:
1. 保持基础处理能力
2. 避免频繁创建销毁核心线程
3. 可通过`allowCoreThreadTimeOut(true)`改变默认行为

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值