栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java 中的 Semaphore 信号量学习小记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java 中的 Semaphore 信号量学习小记

Semaphore 学习小记

Semaphore是JDK提供的一个同步工具,它通过维护若干个许可证来控制线程对共享资源的访问。

信号量的作用是维护一个 “许可证” 的计数,线程可以获取 “许可证”,那信号量剩余的 “许可证” 减一,线程可以释放一个许可证,那 “许可证” 的数量就加一, 当信号量所拥有的许可证是0 时候,那么下一个获取许可证的线程就需要等待,只能有另外的线程释放了许可证。

Semaphore 信号量的使用流程 1.初始化Semaphore并许可证的数量
  • Semaphore(int permits); // 生成指定数量许可证, 排队策略为非公平
  • Semaphore(int permits, boolean fair) // 生成指定数量的许可证,并设置排队策略是否为公平的
2.在需要被许可的地方加 acquire() 相关的方法获取许可证
  • acquire() // 获取许可证并可以相应中断
  • acquireUninterruptibly() // 获取许可证并不可以相应中断
  • tryAcquire() // 如果当前有空闲的许可证直接获取,如果没有如果没有我不必阻塞,我可以先做别的事情
  • tryAcquire(long timeout, TimeUnit unit) // 和tryAcquire()一样,但多了一个超时间的时间,如在三秒内获取不到,我就做别的事情
3.在任务执行结束的时候调用 release() 方法释放许可证 Semaphore 使用
public class SemaphoreDemo {
    // 生成三个许可证
    static Semaphore semaphore = new Semaphore(3);

    public static void main(String[] args) {
        // 定义一个固定数量为 30 个的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(30);
        for (int i = 1; i <= 30; i++) {
            // 生成 30 个任务提交给线程池
            executorService.submit(new Task());
        }
        executorService.shutdown();
    }

    static class Task implements Runnable {
        @Override
        public void run() {
            try {
                // 获取许可证
                semaphore.acquire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 拿到许可证... ");
            try {
                // 暂定任务耗时 2s
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 释放许可证... ");
            // 释放许可证
            semaphore.release();
        }
    }
}

运行结果

Semaphore 信号量的特殊使用

一次性获取或释放多个许可证。比如TaskA会调用很消耗资源的method1(),而TaskB调用的是不太消耗资源的method2(),假设我们一共有5个许可证。那么我们就可以要求TaskA获取5个许可证才能执行而TaskB只需要获取到一个许可证就能执行,这样就避免了A和B同时运行的情况,我们可以根据自己的需求合理分配资源。

Semaphore 信号量使用注意点
  1. 获取和释放的许可证数量必须一致,否则比如每次都获取2个但是只释放1个甚至不释放,随着时间的推移,到最后许可证数量不够用,会导致程序卡死。(虽然信号量类并不对是否和获取的数量做规定,但是这是我们的编程规范,否则容易出错)
  2. 在初始化Semaphore 时候公平性设置为 ture 比较合理,要不然会出现线程饥饿的情况
  3. 并不是必须由获取许可证的线程释放那个许可证,事实上,获取和释放许可证对线程并无要求,也许是A获取了,然后由B释放,只要逻辑合理即可
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/846029.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号