标题 | 链接 |
---|---|
CountDownLatch | Java并发编程之CountDownLatch. |
一、概念
Semaphore令牌。是synchronized的加强版,作用是控制线程的并发数量。
Semaphore是一个计数信号量,它的本质是一个共享锁。信号量维护了一个信号量许可集。线程通过调用acquire()来获取令牌/执行许可。当信号量中还有剩余可使用的令牌时,线程就能获取并且执行完毕后归还。信号量中没有可用令牌,线程必须等待,直到有别的线程释放(归还)令牌为止,线程可以通过release()来释放令牌。
Hystrix中使用Semaphore进行控制并发数量
二、示例
/**
* @author chengyanqi
* @date 2020/7/19 17:49
*/
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "拿到了令牌,执行中..." + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
Thread.sleep(1000);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Thread" + i).start();
}
}
}
Thread0拿到了令牌,执行中...2020-07-19 05:52:43
Thread2拿到了令牌,执行中...2020-07-19 05:52:43
Thread1拿到了令牌,执行中...2020-07-19 05:52:43
Thread4拿到了令牌,执行中...2020-07-19 05:52:44
Thread5拿到了令牌,执行中...2020-07-19 05:52:44
Thread3拿到了令牌,执行中...2020-07-19 05:52:44
Thread6拿到了令牌,执行中...2020-07-19 05:52:45
Thread7拿到了令牌,执行中...2020-07-19 05:52:45
Thread8拿到了令牌,执行中...2020-07-19 05:52:45
Thread9拿到了令牌,执行中...2020-07-19 05:52:46
//可以看出,规定了三个令牌
//强到令牌的线程可以执行
//没抢到的必须等待其他线程释放
三、说明
- Semaphore声明
Semaphore的构造函数接受int型的参数,表示声明的令牌数量,如果在同一时刻允许n个线程获取令牌执行,就传入n - 线程调用semaphore的acquire方法获取令牌,进而执行线程。简单理解为获取锁资源,如果获取不到线程就阻塞
- 线程执行完毕后调用release释放归还令牌。
acquire(int permits):动态添加permits许可数量,表示每次线程占用permits个令牌。
release(int permits):表示释放permits个令牌。
- 当获取令牌数量大于释放令牌时,执行到令牌分发完毕,后续所有线程均会阻塞。
- 当获取令牌数量小于释放令牌时,执行过程中会动态扩容semaphore。如new Sempljore(4)初始化四个令牌,acquire(1)每次拿一个,release(2)每次释放两个。那么第二轮占用时,会有8个线程执行。第三次16个
四、其他常用方法
availablePermits():返回Semaphore中当前可以使用的令牌数。
drainPermits():获取所有当前可用的所有许可令牌,并将令牌池中的令牌置0 。
hasQueuedThreads():判断有没有线程在等待/阻塞
getQueueLength()/hasQueuedThreads():判断在当前有没有等待许可的线程信息使用。
tryAcquire(int permits):尝试获取令牌,boolean类型的值。true表示获取到,false表示没有获取到。不传入参数默认为1
tryAcquire(int permits,long timeout,TimeUint unit):获取permits个令牌,在指定时间timout内尝试,unit是timeout的参数。
/**
* @author chengyanqi
* @date 2020/7/19 17:49
*/
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2,true);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
if (semaphore.tryAcquire(1)) {
System.out.println(Thread.currentThread().getName() + "拿到了令牌,执行中..." + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
Thread.sleep(1000);
semaphore.release(1);
} else {
System.out.println(Thread.currentThread().getName() + "没有获取到令牌");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Thread" + i).start();
}
}
}
Thread2没有获取到令牌
Thread4没有获取到令牌
Thread3没有获取到令牌
Thread1拿到了令牌,执行中...2020-07-19 06:27:17
Thread0拿到了令牌,执行中...2020-07-19 06:27:17