漫画JUC并发包
🎯 学习目标
- 掌握JUC包核心工具类的原理和使用
- 理解并发编程的底层机制
- 掌握高频面试考察点
- 能够在实际项目中正确使用并发工具
📖 故事开始
小明: “老王,我在面试中总是被JUC包的问题难住,什么CountDownLatch、CyclicBarrier、Semaphore,听起来就头疼!”
架构师老王: “哈哈,JUC包确实是Java并发编程的核心,但别担心,我用漫画的方式给你讲解,保证你能轻松掌握!”
小明: “那太好了!先从最基础的开始吧!”
🔐 第一章:锁的艺术 - Lock接口家族
1.1 ReentrantLock - 可重入锁
架构师老王: “想象一下,你家的门锁,你拿着钥匙可以多次进出,这就是可重入锁!”
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
// 可重入性演示
public void increment() {
lock.lock();
try {
count++;
// 同一线程可以再次获取锁
nestedMethod();
} finally {
lock.unlock();
}
}
private void nestedMethod() {
lock.lock(); // 重入锁
try {
count++;
System.out.println("嵌套方法中的count: " + count);
} finally {
lock.unlock();
}
}
// 公平锁演示
private final ReentrantLock fairLock = new ReentrantLock(true);
public void fairLockDemo() {
fairLock.lock();
try {
System.out.println(Thread.currentThread().getName() + " 获得公平锁");
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
fairLock.unlock();
}
}
}
面试考点:
- Q: ReentrantLock与synchronized的区别?
- A: ReentrantLock支持公平锁、可中断、超时获取锁,而synchronized是非公平的
1.2 ReadWriteLock - 读写锁
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Map<String, String> cache = new HashMap<>();
// 读操作 - 多个线程可以同时读
public String get(String key) {
rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " 正在读取");
return cache.get(key);
} finally {
rwLock.readLock().unlock();
}
}
// 写操作 - 只有一个线程可以写
public void put(String key, String value) {
rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " 正在写入");
cache.put(key, value);
} finally {
rwLock.writeLock().unlock();
}
}
}
🚦 第二章:同步工具类 - 控制并发流程
2.1 CountDownLatch - 倒计时门栓
架构师老王: “CountDownLatch就像火箭发射前的倒计时,所有准备工作完成后才能发射!”
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
// 模拟赛跑比赛
public static void raceDemo() throws InterruptedException {
final int RUNNER_COUNT = 5;
CountDownLatch startSignal = new CountDownLatch(1); // 起跑信号
CountDownLatch finishSignal = new CountDownLatch(RUNNER_COUNT); // 完赛信号
// 创建跑步者
for (int i = 0; i < RUNNER_COUNT; i++) {
final int runnerId = i + 1;
new Thread(() -> {
try {
System.out.println("跑步者" + runnerId + "准备就绪");
startSignal.await(); // 等待起跑信号
System.out.println("跑步者" + runnerId + "开始跑步");
Thread.sleep((long) (Math.random() * 3000));
System.out.println("跑步者" + runnerId + "到达终点");
finishSignal.countDown(); // 完赛计数减1
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
Thread.sleep(1000);
System.out.println("裁判:各就各位,预备,跑!");
startSignal.countDown(); // 发出起跑信号
finishSignal.await(); // 等待所有跑步者完赛
System.out.println