博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AQS同步组件--Semaphore
阅读量:7023 次
发布时间:2019-06-28

本文共 3566 字,大约阅读时间需要 11 分钟。

Semaphore

什么是Semaphore?

是用于控制某个资源同一时间被线程访问的个数,提供acquire()和release()方法,acquire获取一个许可,如果没有获取的到就等待,release是在操作完成后释放一个许可,Semaphore维护了当前访问的个数,通过同步机制来控制同时访问的个数,在数据结构里链表中的节点是可以无限个的,而Semaphore里维护的是一个有大小的限链表。

Semaphore的使用场景

Semaphore用于仅能提供有限访问的资源,比如数据库中的链接数只有20但是我们上层应用数可能远大于20,如果同时都对数据库链接进行获取,那很定会因为链接获取不到而报错,所以我们就要对数据库链接的访问进行控制。

演示代码
@Slf4jpublic 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()尝试获取许可成功就执行,尝试获取许可失败就丢弃线程。下面看代码

@Slf4jpublic 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()共提供如下几种方法。

我们用一个例子来演示一下参数的方法的使用。

@Slf4jpublic 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进而执行。

转载地址:http://envxl.baihongyu.com/

你可能感兴趣的文章
Word Excel 操作总结
查看>>
qt 调用zlib压缩与解压缩功能
查看>>
MVVM模式中WPF数据的完全绑定
查看>>
[Hibernate] - one to one
查看>>
【安卓】eclipse中不可错过的几个秘密、!
查看>>
桥接模式
查看>>
设置导航栏标题的文字属性
查看>>
纯银:优秀的人才,没一个开口就问“贵司薪水几何”(转)
查看>>
LoadTestAgentResultsLateException in VS2010
查看>>
开源一个基于nio的java网络程序
查看>>
在Hibernate中使用HibernateTemplate来进行包含sql语句的查询
查看>>
sqlite3经常使用命令&amp;语法
查看>>
Java Collection 简介
查看>>
一个非常不错的背景纹理图的网站
查看>>
WinStore之Application Data
查看>>
word 批量修改表格格式
查看>>
解剖SQLSERVER 第六篇 对OrcaMDF的系统测试里避免regressions(译)
查看>>
memcpy内存拷贝及优化策略图解
查看>>
SQL Server 数据的创建、增长、收缩
查看>>
合并数据
查看>>