Semaphore意思的信号量,它的作用是控制访问特定资源的线程数量
构造方法:
public Semaphore(int permits)
public Semaphore(int permits, boolean fair)
permits:允许同时访问的线程数量
fair:是否公平,若true的话,下次执行的会是先进去等待的线程(先入先出)
使用:
acquire():获取许可执行
release():释放许可,让其他线程获取许可执行。
显然这个功能可以用于资源访问控制或者是限流的操作。
如下代码每次只会有两个线程执行。
package com.nijunyang.concurrent; import java.util.concurrent.Semaphore; /** * Description: * Created by nijunyang on 2020/5/13 23:31 */ public class SemaphoreTest { Semaphore semaphore; public SemaphoreTest(Semaphore semaphore) { this.semaphore = semaphore; } public static void main(String[] args) { SemaphoreTest semaphoreTest = new SemaphoreTest(new Semaphore(2, true)); for (int i = 0; i < 10; i++) { Thread thread = new Thread(() -> { try { semaphoreTest.test(); } catch (InterruptedException e) { e.printStackTrace(); } }, "线程" + i); thread.start(); } System.out.println("线程创建完毕."); } public void test() throws InterruptedException { semaphore.acquire(); System.out.println(Thread.currentThread().getName() + "执行."); Thread.sleep(4000); semaphore.release(); } }
原理:
进入Semaphore的代码一看,又见到AQS,前面ReentrantLock中用到的是独占模式,Semaphore中就是共享模式了。和ReentrantLock如出一辙,内部类Sync继承了AbstractQueuedSynchronizer,同时有两个子类实现一个公平FairSync,另一个非公平NonfairSync。
构造方法传入的permits,最终会赋值到AbstractQueuedSynchronizer的state字段,这个字段的ReentrantLock中是用来计算锁重入的。但是在Semaphore里面字段是用来控制资源访问数量的。
1.acquire方法获取的许可的时候 先去扣减,将state的值-1,如果结果不小于0,就通过CAS操作修改state的值,最后返回当前剩余许可
2. 如果返回的许可剩余数量小于0 就执行doAcquireSharedInterruptibly方法,将当前线程以共享的模式加入到队列中去
3. 拿到前驱结点,根据结点的几个状态去判断前驱结点是否是取消或者其他状态,如果取消状态就剔除出去
4.release方法 释放许可 CAS操作将state的值+1
5.设置成功了执行doReleaseShared方法,去唤醒队列中等待的线程,获取到许可执行