看几个主要方法
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;
}
}
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;
}
}
}
AbstractQueuedSychronizer.class
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
可以看到,当tryAcquireShare小于0时,将线程入列。
当tryReleaseShared为true 时,通知后置节点停止挂起。
AQS里的相关代码,详见之前的AQS文章。
通过上面的源代码可以开出,当state被减到小于0时,后续线程入队挂起。
当release后state 加1,并通知后续节点,停止挂起,进行获取锁操作。
跟前文相比,我们看到CountDown是设置一个state,通过await方法获取锁,当state数量不等于0时,将线程入队并挂起线程。然后通过countDown方法,release锁,将state减一,直到state为0时,依次唤醒后续队列中的线程。
而Semaphore是通过acquire方法,将state减一,当state小于0时,将线程入队挂起。
通过release方法,将state加一,并唤醒后继节点,进而保持同时有state个数的线程在执行。
使用示例
public class SemaphoreTest {
static class MyThread extends Thread{
Semaphore semaphore;
public MyThread(Semaphore semaphore) {
this.semaphore=semaphore;
}
@Override
public void run() {
try {
semaphore.acquire();
Thread.sleep(2000);
System.out.println("thread "+Thread.currentThread().getName()+" sleep done");
}catch (InterruptedException e){
e.printStackTrace();
}finally {
semaphore.release();
}
}
}
public static void main(String[] args) {
int count=50;
Semaphore semaphore=new Semaphore(5);
for (int i=0;i<count;i++){
new MyThread(semaphore).start();
}
System.out.println("main thread run");
}
}
运行结果
main thread run
thread Thread-0 sleep done
thread Thread-3 sleep done
thread Thread-1 sleep done
thread Thread-4 sleep done
thread Thread-2 sleep done
thread Thread-5 sleep done
thread Thread-7 sleep done
thread Thread-9 sleep done
thread Thread-8 sleep done
每次运行五个线程。