Semaphore意思为信号量。用于限制对某一资源的同时访问量。
构造器
public Semaphore(int permits) {sync = new NonfairSync(permits);}
public Semaphore(int permits, boolean fair) {sync = fair ? new FairSync(permits) : new NonfairSync(permits);}
permits是必传项,用于控制访问同一资源的并发数
NonfairSync(int permits) {super(permits);}Sync(int permits) {setState(permits);}
由非公平锁的构造器可以看出,该值存于aqs的volatile修饰的state值
acquire()获取访问资源的信号
public void acquire() throws InterruptedException {sync.acquireSharedInterruptibly(1);//获取aqs共享锁}
这里只分析非公平锁的实现:
public final void acquireSharedInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())//中断标识throw new InterruptedException();if (tryAcquireShared(arg) < 0)//获取锁,小于0,说明共享锁已经用完了doAcquireSharedInterruptibly(arg);//加入aqs队列}
protected int tryAcquireShared(int acquires) {return nonfairTryAcquireShared(acquires);}
final int nonfairTryAcquireShared(int acquires) {for (;;) {int available = getState();//获取当前state状态(剩余信号量)int remaining = available - acquires;//减去当前需要的信号量if (remaining < 0 ||//小于0,获取不到信号量compareAndSetState(available, remaining))//cas去抢占信号量return remaining;}}
源码可以看出,每个线程过来都用cas操作state-1去获取信号.如果小于0说明信号量已经被使用完毕。
如果信号量aqs,使用完毕,则加入aqs队列
private void doAcquireSharedInterruptibly(int arg)throws InterruptedException {final Node node = addWaiter(Node.SHARED);//创建等待节点,并将节点加入aqs队列boolean failed = true;try {for (;;) {final Node p = node.predecessor();if (p == head) {//前节点是head节点int r = tryAcquireShared(arg);//去抢占资源if (r >= 0) {//抢占成功setHeadAndPropagate(node, r);p.next = null; // help GCfailed = false;return;}}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}}
release()去释放信号
public void release() {sync.releaseShared(1);}
通过同步器去释放锁
public void release() {sync.releaseShared(1);}
public final boolean releaseShared(int arg) {if (tryReleaseShared(arg)) {//释放共享锁doReleaseShared();//唤醒aqs队列中等待的队列return true;}return false;}
释放共享锁。及通过cas让state+1
protected final boolean tryReleaseShared(int releases) {for (;;) {//自旋int current = getState();int next = current + releases;if (next < current) // overflowthrow new Error("Maximum permit count exceeded");if (compareAndSetState(current, next))//cas去加回statereturn true;}}
释放后唤醒aqs中等待的头节点
private void doReleaseShared() {for (;;) {Node h = head;if (h != null && h != tail) {int ws = h.waitStatus;if (ws == Node.SIGNAL) {if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))continue; // loop to recheck casesunparkSuccessor(h);//唤醒排在第一的线程}else if (ws == 0 &&!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))continue; // loop on failed CAS}if (h == head) // loop if head changedbreak;}}
这里只分析非公平锁,公平锁的差异只是在抢占锁之前,会先分析aqs队列中是否有等待队列,如果有的话,不尝试获取,而是直接加入aqs队列。
