共享锁,用于类似多个窗口排队买票的场景,可以同时进行多个线程的处理,超出的入队等待
实现:
/*业务场景:现在又20个人排队买票,但是窗口只有三个,一个窗口一次只能让一个线程买票*/Semaphore semaphore = new Semaphore(3);for (int i = 0; i < 20; i++) {new Thread(()->{try {// 加锁semaphore.acquire();System.out.println(Thread.currentThread().getName() + "正在买票");Thread.sleep(5000L);System.out.println(Thread.currentThread().getName() + "买票完成");} catch (InterruptedException e) {e.printStackTrace();}finally {// 释放semaphore.release();}}).start();}输出:Thread-0正在买票Thread-1正在买票Thread-2正在买票5S:Thread-1买票完成Thread-2买票完成Thread-3正在买票Thread-0买票完成Thread-4正在买票Thread-5正在买票...
上面例子中给sleep添加一个条件可以看出一个线程释放了立马就会有一个线程就执行
if(!Thread.currentThread().getName().equals("Thread-0")){Thread.sleep(5000L);}
原理
默认实现的非公平的实现方式
同时也能传入参数自行调整公平与非公平
初始化时会给state赋值,值为传入的参数,设置信号量
加锁过程:
semaphore.acquire();public void acquire() throws InterruptedException {sync.acquireSharedInterruptibly(1);}public final void acquireSharedInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();// tryAcquireShared中尝试加锁if (tryAcquireShared(arg) < 0)// 没有拿到锁就入队doAcquireSharedInterruptibly(arg);}// 获取资源的逻辑// acquires == 1final int nonfairTryAcquireShared(int acquires) {for (;;) {// 拿到现在的stateint available = getState();// 减去传入的间隔int remaining = available - acquires;if (remaining < 0 ||compareAndSetState(available, remaining)) // CAS修改return remaining;}}
Semaphore在解锁的时候哟传播的特性,当先线程唤醒了修改了state的值去执行,他会判断当下线程的下一个节点的waitState是不是-1(-1代表可以被唤醒),要是等于-1就唤醒下一个线程去尝试竞争资源,不行就休眠
