美文网首页
JUC-Semaphore

JUC-Semaphore

作者: 别拿爱情当饭吃 | 来源:发表于2018-10-24 20:15 被阅读17次

一、什么是Semaphore?

计数信号量

二、Semaphore有什么用途?

像是一个装着资源的容器

三、Semaphore应用场景

学生饭堂打饭

四、代码测试

以下测试的是Semaphore的API


Semaphore semaphore_nofair = new Semaphore(5);//默认是非公平锁

Semaphore semaphore_fair = new Semaphore(5, true);

//isFair()

System.out.println("是否公平FIFO:" + semaphore_fair.isFair());

System.out.println("是否公平FIFO:" + semaphore_nofair.isFair());

//avaliablePermits():获取当前可用的许可证数量

try {

semaphore_fair.acquire();

semaphore_fair.acquire(3);//acquire是消耗资源

semaphore_fair.release(10);//release是创建资源

semaphore_fair.acquire(6);

semaphore_nofair.acquire(3);

semaphore_nofair.release(10);

semaphore_nofair.acquire(6);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("获取当前可用的许可证数量:开始---" + semaphore_fair.availablePermits());//5

System.out.println("获取当前可用的许可证数量:开始---" + semaphore_nofair.availablePermits());//6

五、源码解析

有三个内部类,一个是普通的Sync类(父类),一个公平的FairSync(子类),一个是非公平的NonFairSync(子类)

1.Sync类

abstract static class Sync extends AbstractQueuedSynchronizer {

private static final long serialVersionUID = 1192457210091910933L;

Sync(int permits) {

setState(permits);

}

//获取有多少许可证

final int getPermits() {

return getState();

}

//非公平锁的获取

final int nonfairTryAcquireShared(int acquires) {

for (;;) {

int available = getState();

int remaining = available - acquires;

if (remaining < 0 ||

compareAndSetState(available, remaining))

return remaining;

}

}

//尝试释放共享锁,释放成功就调用CAS来重置许可证的数量,然后返回true

protected final boolean tryReleaseShared(int releases) {

for (;;) {

int current = getState();

int next = current + releases;

if (next < current) // overflow

throw new Error("Maximum permit count exceeded");

if (compareAndSetState(current, next))

return true;

}

}

//减少许可证的数量,也是调用CAS

final void reducePermits(int reductions) {

for (;;) {

int current = getState();

int next = current - reductions;

if (next > current) // underflow

throw new Error("Permit count underflow");

if (compareAndSetState(current, next))

return;

}

}

//获取剩余的许可证,然后调用CAS

final int drainPermits() {

for (;;) {

int current = getState();

if (current == 0 || compareAndSetState(current, 0))

return current;

}

}

}

2.NonFairSync和FairSync

/**

* 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);//调用父类Sync的方法

}

}

/**

* Fair version

*/

static final class FairSync extends Sync {

private static final long serialVersionUID = 2014338818796000944L;

FairSync(int permits) {

super(permits);

}

protected int tryAcquireShared(int acquires) {

for (;;) {

if (hasQueuedPredecessors())

return -1;

int available = getState();

int remaining = available - acquires;

if (remaining < 0 ||

compareAndSetState(available, remaining))

return remaining;

}

}

}

二者区别:FairSync与NonFairSync的区别就在于会首先判断当前队列中有没有线程在等待,如果有,就老老实实进入到等待队列;而不像NonfairSync一样首先试一把,说不定就恰好获得了一个许可,这样就可以插队了。

3.构造方法

public Semaphore(int permits) {

sync = new NonfairSync(permits);//默认是非公平

}

/**

* Creates a {@code Semaphore} with the given number of

* permits and the given fairness setting.

*

* @param permits the initial number of permits available.

* This value may be negative, in which case releases

* must occur before any acquires will be granted.

* @param fair {@code true} if this semaphore will guarantee

* first-in first-out granting of permits under contention,

* else {@code false}

*/

public Semaphore(int permits, boolean fair) {

sync = fair ? new FairSync(permits) : new NonfairSync(permits);

}

4.普通方法

//获取或消耗一个资源(可中断)

public void acquire() throws InterruptedException {

sync.acquireSharedInterruptibly(1);

}

//获取或消耗n个资源(可中断)

public void acquire(int permits) throws InterruptedException {

if (permits < 0) throw new IllegalArgumentException();

sync.acquireSharedInterruptibly(permits);

}

//获取或消耗一个不可中断资源

public void acquireUninterruptibly() {

sync.acquireShared(1);

}

//获取或消耗n个不可中断资源

public void acquireUninterruptibly(int permits) {

if (permits < 0) throw new IllegalArgumentException();

sync.acquireShared(permits);

}

//创建或释放一个资源

public void release() {

sync.releaseShared(1);

}

//创建或释放n个资源

public void release(int permits) {

if (permits < 0) throw new IllegalArgumentException();

sync.releaseShared(permits);

}

//获取当前有多少个资源

public int availablePermits() {

return sync.getPermits();

}
/**

* Acquires and returns all permits that are immediately available.

*

* @return the number of permits acquired

*/

//获取并消耗当前有多少个资源,调用此方法后,资源数量变为0

public int drainPermits() {

return sync.drainPermits();

}

//减少n个资源

protected void reducePermits(int reduction) {

if (reduction < 0) throw new IllegalArgumentException();

sync.reducePermits(reduction);

}

//当前的Semaphore是否是公平的

public boolean isFair() {

return sync instanceof FairSync;

}
/**

* Queries whether any threads are waiting to acquire. Note that

* because cancellations may occur at any time, a {@code true}

* return does not guarantee that any other thread will ever

* acquire. This method is designed primarily for use in

* monitoring of the system state.

*

* @return {@code true} if there may be other threads waiting to

* acquire the lock

*/

//当前是否有等待的资源的线程

public final boolean hasQueuedThreads() {

return sync.hasQueuedThreads();

}
/**

* Returns an estimate of the number of threads waiting to acquire.

* The value is only an estimate because the number of threads may

* change dynamically while this method traverses internal data

* structures. This method is designed for use in monitoring of the

* system state, not for synchronization control.

*

* @return the estimated number of threads waiting for this lock

*/

//当前等待资源的线程有多少个

public final int getQueueLength() {

return sync.getQueueLength();

}

六、总结:

Semaphore是信号量,用于管理一组资源。其内部是基于AQS的共享模式,AQS的状态表示许可证的数量,在许可证数量不够时,线程将会被挂起;而一旦有一个线程释放一个资源,那么就有可能重新唤醒等待队列中的线程继续执行。

相关文章

  • JUC-Semaphore

    一、什么是Semaphore? 计数信号量 二、Semaphore有什么用途? 像是一个装着资源的容器 三、Sem...

  • JUC-Semaphore

      信号量目的:1)用于多个共享资源的互斥使用 2)用于并发线程数的控制。(多对多)   Semaphore可以控...

网友评论

      本文标题:JUC-Semaphore

      本文链接:https://www.haomeiwen.com/subject/rxzxtqtx.html