目录
Semaphore许可证
Semaphore原理分析
Semaphore方法总结
Semaphore总结
Semaphore许可证Semaphore是一种线程同步工具,主要用于同时允许一定数量的线程并行操作共享资源的场景。
Semaphore可用于限制用户数相似的场景,如停车场和高峰酒店位置。
首先,举个例子看看它的使用方法。
publicstaticvoidmain (字符串[ ] args )//10个finalintpermits=10;//定义10个Semaphore许可证的finalsemaphoresemaphore=new semaphore (permits,true ); //20个线程的intstream.range (0,20 ).foreach I-{ new thread } )-{ boolean flag=semaphore.try acquire } ); if(flag ) (system.out.println ) Thread.currentThread ) (.getName )、“许可证获取”); } else { system.out.println (thread.current thread ().getName )“未获得许可”}try{//许可后模拟业务处理}finally{semaphore.release (; system.out.println (thread.current thread ().getName )“发布许可证”); },'线程-' i ).start ); ); }私密性staticvoidsleep ((try ) timeunit.seconds.sleep ) newrandom ).nextInt(3) )3); } catch (互联互通) {e.printStackTrace ); }在上述代码中,我们创建了10个许可证,并选中了复选框。 这意味着最多有10个线程同时运行。
Semaphore对象的许可数量和许可方式根据参与结构制定了公平的方式。
tryAcquire ()是一种获取不阻止线程、获取许可证并返回true、无法获取并返回false的许可证的方法。
release ) )获得许可证的线程必须在运行结束后释放许可证。 为了保证许可证的释放(release ) )方法通常写在finally语句块中。
Semaphore原理分析Semaphore的实现原理是什么? 接下来和复选标记一起看源代码吧。
Semaphore是基于AQS共享模型的实现,其维护的内部类实现了AbstractQueuedSynchronizer。
在Semaphore中,state表示许可证计数,因为Semaphore在构建时指定许可证计数是用于指定AQS同步器状态状态的值。
也可以指定在构建Semaphore时获取许可的公平或不公平方法,默认值为不公平获取方法。
Semaphore重写以共享模式许可的tryAcquireShared ()和释放许可的tryReleaseShared ) )方法,其中内部类的NonfairSync和FairSync不同
内部类Sync源代码的注释如下:
abstractstaticclassyncextendsabstractqueuedsynchronizer { privatestaticfinallongserialversionuid=1}
192457210091910933L; //有参构造,permits即是state的值 Sync(int permits) { setState(permits); } //获取许可证数量,即获取state同步器状态值 final int getPermits() { return getState(); } //非公平方式获取操作 final int nonfairTryAcquireShared(int acquires) { for (;;) { //获取剩余许可证数量 int available = getState(); //将剩余许可证减去当前线程想要获取的许可证数量 int remaining = available - acquires; //如果小于0,则返回剩余的许可证数量,是个负值 //如果不小于0,则通过CAS修改state的值,修改成功则返回剩余数量,是个正值 //如果CAS失败,则一直循环 if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } } //共享方式释放操作 protected final boolean tryReleaseShared(int releases) { for (;;) { //获取state的值 int current = getState(); //将state的值加上当前线程要释放的许可数量 int next = current + releases; //如果释放之后的许可数量小于当前数量,则抛异常 if (next < current) // overflow throw new Error("Maximum permit count exceeded"); //cas修改state的值,修改成功返回true,失败返回false if (compareAndSetState(current, next)) return true; } }}NonfairSync非公平类,其获取许可的操作直接调用了父类Sync的nonfairTryAcquireShared()方法。
/** * NonFair version */static final class NonfairSync extends Sync { private static final long serialVersionUID = -2694183684443567898L; NonfairSync(int permits) { super(permits); } protected int tryAcquireShared(int acquires) { return nonfairTryAcquireShared(acquires); }}FairSync公平类,其自己实现了tryAcquireShared()方法。
static final class FairSync extends Sync { private static final long serialVersionUID = 2014338818796000944L; FairSync(int permits) { super(permits); } protected int tryAcquireShared(int acquires) { for (;;) { //判断当前线程节点是否为下一个要唤醒的节点,不是则返回-1 if (hasQueuedPredecessors()) return -1; //如果是下一个要唤醒的节点,则尝试获取许可 int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } }}我们之前《AQS之共享模式》一文中学习了AQS共享模式的原理,我们了解到tryAcquireShared()方法返回小于0的数值则表示线程获取许可失败,返回大于0的数值则表示线程许可成功。
获取失败之后会怎么样呢?
《AQS之共享模式》给你答案喔!
Semaphore基本流程:
Semaphore方法总结Semaphore构造器
Semaphore(int permits):定义Semaphore指定许可数量,并且默认非公平的方式获取许可。
Semaphore(int permits, boolean fair):定义Semaphore指定许可数量以及同步方式。
获取方法
acquire():当前线程调用此方法获取许可证,获取不到会进入阻塞状态一直等待,直到Semaphore有可用的许可或者被其他线程打断。如果Semaphore有可用的许可,该方法会立即返回。
acquire(int permits):当前线程调用该方法会向Semaphore获取指定permits的许可数量,permits不能小于0。该方法作用与acquire()一样,只是指定了获取的许可数量,acquire()是获取一个许可数量。
acquireUninterruptibly():当前线程调用此方法获取许可,如果获取不到会一直阻塞而且不能被打断,直到Semaphore有可用许可才能退出阻塞。此方法一般不用,因为可能会导致大规模的线程阻塞而导致Java进程假死现象。
acquireUninterruptibly(int permits):该方法与acquireUninterruptibly()作用一样,只是可以指定获取permits个许可数量,permits不能小于0。
tryAcquire():尝试获取许可数量,只会向Semaphore申请一个许可数量,如果Semaphore的许可数量大于等于1,将会获取成功返回true,否则将会获取许可失败返回false。
tryAcquire(long timeout, TimeUnit unit):尝试获取许可数量,也是只申请一个许可,但是它增加了超时参数。如果在超时的时间内还是没有可用的许可,当前线程会进入阻塞状态,直到达到超时时间或者超时时间内获得了许可,或者阻塞线程被其他线程打断。
tryAcquire(int permits):该方法与tryAcquire()作用一样,只是可以指定获取permits个许可数量,permits不能小于0。
tryAcquire(int permits, long timeout, TimeUnit unit):该方法可以获取permits个许可数量,并且可以设置超时时间。
释放操作
release():释放一个许可证,Semaphore内部的许可证数量会加1,表示多了1个可用的许可。
release(int permits):释放permits个许可证,Semaphore内部的许可证数量会加permits。permits不能小于0。
Semaphore总结
Semaphore可以允许一定数量的线程对共享资源进行访问,并且提供了丰富的获取操作:阻塞或者不阻塞,中断或者不中断、获取多个许可或者一个许可。
Semaphore虽然可以控制并发的线程数量,但是对共享资源的数据安全并没有提供任何保证,所以如果涉及到了共享可变资源的并发需要额外的控制。
如果在开发中使用了不阻塞的方式获取许可数量,需对返回结果进行处理,否则可能出现尝试获取许可失败却依然执行了业务逻辑。
好了今天就到这里,祝福大家周末愉快 !!!
下一篇文章是最后一个JUC工具类Phaser,哇哇哇,看到光明了!!!