引言:
Semaphore类,也叫信号量,用来协调线程的访问,通过控制同时访问某个特定资源或执行某个特殊操作的线程数量来实现资源的协调。
Semaphore类实现简介:
Semaphore类中维护了若干个许可证,许可证的数量可以通过构造函数的参数指定。
在线程访问特定资源前,必须使用acquire方法获得许可证,如果许可证数量为0,则线程一直阻塞,直到有可用许可证。
在线程访问资源后,Semaphore类使用release释放许可证。
Semaphore类源码分析:
1. 构造函数分析
构造函数如下图所示,permits为限制访问参数,默认使用非公平锁,也可以使用true/false设置是否公平锁。使用AQS类的state变量存放剩余的许可证数量。
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
2. 非公平锁抢占资源实现
步骤1.得到当前资源剩余的许可证
步骤2.剩余许可证数量-请求的许可证数量,赋给remaining
步骤3.如果remaining<0,更新剩余许可证数量为remaining。
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
3.公平锁的抢占资源
非公平锁与公平锁相比,多了hasQueuedPredecessors方法,该方法判断是否存在同步队列排队线程,如果存在,返回抢占失败。
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;
}
}
4.资源释放过程
步骤1.剩余许可证数量+请求的许可证数量,赋给next
步骤2.更新state字段
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;
}
}
5.使用实例
如下图所示,使用Semaphore类限制连接池访问数量。
public class SemaphoreTest{
public static void main(String[] args) throws Exception {
ExecutorService executors = Executors.newCachedThreadPool();
for (int i = 0; i < 20; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
Connection.getInstance().connect();
}
});
}
executorService.awaitTermination(10, TimeUnit.HOURS);
}
}
class Connection {
private static Connection instance = new Connection();
private Semaphore semaphores = new Semaphore(5,true);
private int connectionNum = 0;
private Connection() {
}
public static Connection getInstance() {
return instance;
}
public void connect() {
try {
semaphores.acquire();
doConnect();
} catch (InterruptedException e) {
//
}finally {
semaphores.release();
}
}
private void doConnect() {
synchronized (this) {
connectionNum++;
System.out.println("current connections num: " + connectionNum);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//
}
synchronized (this) {
connectionNum --;
System.out.println("current connections num : " + connectionNum);
}
}
}
附图:
感兴趣的小伙伴请关注本人公众号:暖爸的java家园