📢 【夜店风云】Semaphore:线程们的857蹦迪现场!保安:里面人满了,排队去!
🌃 夜店名场面:线程の狂欢
深夜12点,**"Semaphore夜店"**门口大排长龙!
线程A(穿着new关键字潮牌):“我有VIP,让我先进!”
线程B(顶着黑眼圈):“我刚release()出来,怎么又要排队?!”
线程C(996刚下班):“我就想acquire()个卡座,这么难吗?”
保安(Semaphore)冷着脸:“里面就3个舞池位置,出来一个才能进一个!”
(画外音:当你的代码试图同时操作100个线程访问数据库连接池时,数据库:“我裂开了!”)
🎫 Semaphore是什么?
它就像夜店保安手里的入场券:
许可证总量:夜店容量(比如3个卡座)
acquire():抢到券才能进(没券?门口等着!)
release():嗨完离场,退还入场券
代码版夜店蹦迪:
Semaphore semaphore = new Semaphore(3); // 只有3个舞池位置IntStream.range(0, 10).forEach(i -> new Thread(() -> {try {semaphore.acquire(); // 求求了,给张票吧System.out.println("线程"+i+"进入舞池!开始857!");Thread.sleep(2000); // 疯狂摇摆} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {semaphore.release(); // 跳累了,溜了溜了System.out.println("线程"+i+"离开舞池!");}}).start());
输出:
线程0进入舞池!开始857!线程1进入舞池!开始857!线程2进入舞池!开始857!(2秒后)线程0离开舞池!线程3进入舞池!开始857!...
🔍 原理解密:AQS的限量人生
Semaphore的核心是许可证计数器:
state变量:记录剩余入场券数量
非公平模式(默认):新线程可以插队抢票(VIP特权!)
公平模式:严格按先来后到排队(保安:都给我老实等着!)
CLH队列:没抢到票的线程在虚拟队列里蹲着
(画外音:当你在代码里用new Semaphore(3, true)
时,保安秒变正义使者:“排队!必须排队!”)
👨💻 手搓"夜店保安系统"(乞丐版)
用synchronized+wait/notify实现最简Semaphore:
public class MySemaphore {private int permits;public MySemaphore(int permits) {this.permits = permits;}public synchronized void acquire() throws InterruptedException {while (permits <= 0) {wait(); // 保安:没票了,一边等着!}permits--; // 成功抢到票}public synchronized void release() {permits++; // 退还入场券notifyAll(); // 保安喊:有人出来了!}}
测试代码:
MySemaphore semaphore = new MySemaphore(2); // 卫生间只有2个坑位new Thread(() -> {try {semaphore.acquire();System.out.println("线程A占领坑位...");Thread.sleep(3000); // 带薪拉屎} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {semaphore.release();}}).start();// 其他线程同理...
💣 夜店潜规则(避坑指南)
release()不能不调:离场不还券?夜店迟早倒闭(内存泄漏警告!)
信号量别乱增:
release()
超过初始值?保安:“我凭空变出个卡座?”tryAcquire()灵活用:
if(tryAcquire()) { 蹦迪 } else { 回家 }
—— 拒绝死等!小心信号量劫持:比如用
semaphore.acquire(permits)
一次性抢光所有票(包场玩法!)
🎮 实战:数据库连接池
public class ConnectionPool {private final Semaphore semaphore;private final Deque<Connection> pool = new ArrayDeque<>();public ConnectionPool(int size) {this.semaphore = new Semaphore(size);IntStream.range(0, size).forEach(i ->pool.add(createConnection()); // 创建连接}public Connection getConn() throws InterruptedException {semaphore.acquire(); // 等入场券synchronized (pool) {return pool.removeFirst();}}public void releaseConn(Connection conn) {synchronized (pool) {pool.addLast(conn);}semaphore.release(); // 还券}}
(画外音:当你的同事忘记release()时,整个系统逐渐变成——“连接池已空,等不到的永远在骚动~”)
👉 关注【让天下没有难学的编程】
下期预告:《ThreadLocal:线程的私房钱保险柜——谁也别想动我的变量!》
彩蛋:
当主线程试图用Semaphore控制子线程时:
Semaphore semaphore = new Semaphore(0);new Thread(() -> {doSomething();semaphore.release(); // 工具人实锤}).start();semaphore.acquire(); // 主线程:“你不干完活别想走!”
(保安:这届线程太难带了,还得当监工!)




