内容简介:是用于控制某个资源同一时间被线程访问的个数,提供acquire()和release()方法,acquire获取一个许可,如果没有获取的到就等待,release是在操作完成后释放一个许可,Semaphore维护了当前访问的个数,通过同步机制来控制同时访问的个数,在数据结构里链表中的节点是可以无限个的,而Semaphore里维护的是一个有大小的限链表。Semaphore用于仅能提供有限访问的资源,比如数据库中的链接数只有20但是我们上层应用数可能远大于20,如果同时都对数据库链接进行获取,那很定会因为链接获取不
Semaphore
什么是Semaphore?
是用于控制某个资源同一时间被线程访问的个数,提供acquire()和release()方法,acquire获取一个许可,如果没有获取的到就等待,release是在操作完成后释放一个许可,Semaphore维护了当前访问的个数,通过同步机制来控制同时访问的个数,在数据结构里链表中的节点是可以无限个的,而Semaphore里维护的是一个有大小的限链表。
Semaphore的使用场景
Semaphore用于仅能提供有限访问的资源,比如数据库中的链接数只有20但是我们上层应用数可能远大于20,如果同时都对数据库链接进行获取,那很定会因为链接获取不到而报错,所以我们就要对数据库链接的访问进行控制。
演示代码
@Slf4j
public class SemaphoreExample1 {
private final static int threadCount = 20;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
semaphore.acquire(); // 获取一个许可
test(threadNum);
semaphore.release(); // 释放一个许可
} catch (Exception e) {
log.error("exception", e);
}
});
}
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
log.info("{}", threadNum);
Thread.sleep(1000);
}
}
我们在执行 test(threadNum)方式前后包裹上acquire和release,这样其实我们就相当于一个单线程在执行。当执行acquire后就只能等待执行release后再执行新的线程,然后我们在acquire()和release()都是没有传参也就是1,每次只允许一个线程执行,如果我们改成
semaphore.acquire(3); // 获取多个许可 test(threadNum); semaphore.release(3); // 释放多个许可
那么我们就是每3个3个执行直到把线程池中的线程执行完。在打印的日志中我们也可以看到是每三个每三个打印。
假设我们的数据库允许获取连接是3剩余的获取线程我们不想要只想丢弃改如何实现?
Semaphore提供了一个尝试获取许可的方法,tryAcquire()尝试获取许可成功就执行,尝试获取许可失败就丢弃线程。下面看代码
@Slf4j
public class SemaphoreExample3 {
private final static int threadCount = 20;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
if (semaphore.tryAcquire()) { // 尝试获取一个许可
test(threadNum);
semaphore.release(); // 释放一个许可
}
} catch (Exception e) {
log.error("exception", e);
}
});
}
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
log.info("{}", threadNum);
Thread.sleep(1000);
}
}
这段代码执行结果就只打印了3行日志,其他的线程就被丢弃了。tryAcquire()共提供如下几种方法。
我们用一个例子来演示一下参数的方法的使用。
@Slf4j
public class SemaphoreExample4 {
private final static int threadCount = 20;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
if (semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS)) { // 尝试获取一个许可
test(threadNum);
semaphore.release(); // 释放一个许可
}
} catch (Exception e) {
log.error("exception", e);
}
});
}
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
log.info("{}", threadNum);
Thread.sleep(1000);
}
}
这次我们使用的是一个tryAcquire(5000, TimeUnit.MILLISECONDS))方法,这个方法的第一个参数是表示等待5000毫秒,第二参数是表示多长时间尝试一次,TimeUnit.MILLISECONDS表示1毫秒。这时候我们会发现20个线程都执行了,为什么会这样呢?因为我们在执行时等待超时时间是5秒,每次执行就是sleep 1秒,所以可以获取成tryAcquire进而执行。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- AQS同步组件--CyclicBarrier
- AQS同步组件--ReentrantLock与锁
- 数据源管理 | 基于DataX组件,同步数据和源码分析
- MySQL读写分离及主从同步延时问题解决思路深入剖析-综合组件环境实战
- 多人游戏的网络实现:帧同步和状态同步
- MySQL主从同步机制和同步延时问题追查
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
人人都是产品经理
苏杰 / 电子工业出版社 / 2010年4月 / 45.00元
这是写给“-1到3岁的产品经理”的书,适合刚入门的产品经理、产品规划师、需求分析师,以及对做产品感兴趣的学生,用户体验、市场运营、技术部门的朋友们,特别是互联网、软件行业。作为一名“4岁的产品经理”,作者讲述了过去3年的经历与体会,与前辈们的书不同,本书就像你走到作者身边,说“嗨哥们!晚上有空吃个饭么,随便聊聊做产品的事吧”,然后作者说“好啊”。 书名叫“人人都是产品经理”,是因为作者觉得过......一起来看看 《人人都是产品经理》 这本书的介绍吧!