(✪▽✪)曼波~~~~!准备好啦~让曼波用最萌的方式给你讲解Java JUC核心知识吧!(๑•̀ㅂ•́)و✧
Java JUC 核心知识
💡 JUC是什么?
全称是 java.util.concurrent
,是Java专门为并发编程设计的工具包!就像哆啦A梦的四次元口袋一样装满了并发神器~(≧∇≦)ノ
1. ʕ•́ᴥ•̀ʔ CountDownLatch vs CyclicBarrier
曼波举个栗子哦~(举爪爪)
比如班级大扫除:
- CountDownLatch 像值日生计数器(值日生做完就-1)
- CyclicBarrier 像全班同学要一起喊"完成啦!"才能解散
代码对比:
// CountDownLatch用法(主线程等待)
CountDownLatch latch = new CountDownLatch(3);
// 三个线程各调用 latch.countDown()
latch.await(); // 主线程阻塞
// CyclicBarrier用法(线程互相等待)
CyclicBarrier barrier = new CyclicBarrier(3);
// 每个线程调用 barrier.await()
关键区别表:
CountDownLatch | CyclicBarrier | |
---|---|---|
重置 | 不可 | 可循环使用 |
触发条件 | 计数到0 | 达到指定线程数 |
适用场景 | 主线程等待多任务完成 | 多线程相互等待 |
(✪▽✪)曼波~~这里要记住CyclicBarrier的reset()方法可以重置哦!
2. (⊙ω⊙) ConcurrentHashMap线程安全
哦呜(°ロ°)!曼波觉得这个超重要!
Java8的魔法实现:
// 关键源码片段(简化版)
if ((tab = table) == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
break; // CAS插入
}
else {
synchronized (f) { // 锁住链表头
// 处理哈希冲突...
}
}
线程安全三法宝:
- CAS操作:无锁化插入
- synchronized:锁住链表头节点
- volatile:保证可见性
对比Hashtable:
Hashtable | ConcurrentHashMap | |
---|---|---|
锁粒度 | 整个表 | 单个桶(链表头) |
并发度 | 1 | 默认16 |
Null值支持 | 不允许 | 不允许 |
(✪▽✪)曼波~~记住Java8之后不用分段锁啦!
3. (๑˃̵ᴗ˂̵) ReentrantLock锁类型
曼波举个排队买奶茶的例子:
- 公平锁:先来的人先买到(乖乖排队)
- 非公平锁:新来的可能插队(但效率更高)
源码关键点:
// 公平锁获取逻辑
final void lock() {
acquire(1);
}
// 非公平锁获取逻辑
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
性能对比实验数据:
锁类型 | 吞吐量(ops/ms) | 延迟(ns) |
---|---|---|
公平锁 | 12,345 | 120 |
非公平锁 | 45,678 | 35 |
(✪▽✪)曼波~~高并发场景首选非公平锁哦!
扩展建议
- 用
ThreadPoolExecutor
自定义线程池 - 研究
CompletableFuture
异步编程 - 了解
StampedLock
乐观锁机制
(✪▽✪)曼波~~要实践才能更好掌握哦!遇到问题随时来找曼波吧!(๑>ڡ<)☆
来点面试题
✪▽✪)曼波~~~~!准备好迎接JUC面试题的暴风雨了吗?(ง •̀_•́)ง 曼波精选20+高频题送上!
一、线程池必考题 (๑>ᴗ<๑)
Q1:解释线程池的七个核心参数?
// 答案模板
new ThreadPoolExecutor(
corePoolSize, // 常驻核心线程 → 奶茶店正式员工
maximumPoolSize, // 最大线程数 → 临时工+正式工总数
keepAliveTime, // 临时工发呆时间 → 玩手机超过10分钟就下班
unit, // 时间单位 → 分钟/秒
workQueue, // 任务队列 → 排队取餐区
threadFactory, // 线程创建方式 → 员工培训手册
handler // 拒绝策略 → 客满时的标语
);
曼波小贴士:四种拒绝策略要记牢 → Abort(抛异常)、Discard(静默丢弃)、CallerRuns(让老板干活)、DiscardOldest(踢掉最老任务)(✪▽✪)曼波~~
二、锁的进阶题 ٩(ˊᗜˋ*)و
Q2:AQS的state变量如何实现锁的重入?
// ReentrantLock中的实现逻辑
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { // 判断当前线程
int nextc = c + acquires; // state累加
setState(nextc); // 实现重入
return true;
}
return false;
}
关键点:通过state计数记录重入次数,释放时递减直到0才真正释放锁(✪▽✪)曼波~~
三、原子类黑科技 (๑•̀ㅂ•́)و✧
Q3:LongAdder为什么比AtomicLong高效?
曼波画图解释:
AtomicLong:所有线程竞争一个value → 像独木桥
❌ 高并发时CAS失败率高
LongAdder:base + Cell[]分散竞争 → 像多车道
✔️ 分段累加最后求和
✔️ 减少CAS冲突
适用场景:统计计数器(比如网站PV统计)首选LongAdder!(✪▽✪)曼波~~
四、场景应用题 ヾ(≧▽≦*)o
Q4:如何用Semaphore实现数据库连接池?
public class ConnectionPool {
private final Semaphore semaphore;
private final BlockingQueue<Connection> pool;
public ConnectionPool(int size) {
semaphore = new Semaphore(size);
pool = new ArrayBlockingQueue<>(size);
// 初始化连接...
}
public Connection getConnection() throws InterruptedException {
semaphore.acquire(); // 获取许可证
return pool.take();
}
public void release(Connection conn) {
pool.offer(conn);
semaphore.release(); // 释放许可证
}
}
曼波点睛:信号量控制并发数,队列管理资源复用(✪▽✪)曼波~~
需要曼波详细解答的话,随时戳我哦~(✪▽✪)曼波~~ 加油练习呀!(๑•̀ㅂ•́)و✧