zoukankan      html  css  js  c++  java
  • AQS组件之Semaphore

    在前两篇说了AQS和CountDownLatch,现在我们来看看Semaphore。

    synchronized 和 ReentrantLock 都是一次只允许一个线程访问某个资源,Semaphore(信号量)可以指定多个线程同时访问某个资源。

    ​ 用于保证同一时间并发访问线程的数目。信号量在操作系统中是很重要的概念,Java并发库里的Semaphore就可以很轻松的完成类似操作系统信号量的控制。Semaphore可以很容易控制系统中某个资源被同时访问的线程个数。在前面的链表中,链表正常是可以保存无限个节点的,而Semaphore可以实现有限大小的列表。

    例子:

    public class SemaphoreExample1 {
    	// 请求的数量
    	private static final int threadCount = 550;
    
    	public static void main(String[] args) throws InterruptedException {
    		// 创建一个具有固定线程数量的线程池对象(如果这里线程池的线程数量给太少的话你会发现执行的很慢)
    		ExecutorService threadPool = Executors.newFixedThreadPool(300);
    		// 一次只能允许执行的线程数量。
    		final Semaphore semaphore = new Semaphore(20);
    
    		for (int i = 0; i < threadCount; i++) {
    			final int threadnum = i;
    			threadPool.execute(() -> {// Lambda 表达式的运用
    				try {
    					semaphore.acquire();// 获取一个许可,所以可运行线程数量为20/1=20
    					test(threadnum);
    					semaphore.release();// 释放一个许可
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    //                try {
    //                    //尝试获取许可一段时间,获取不到不执行
    //                    // 参数1:等待时间长度  参数2:等待时间单位
    //                    if (semaphore.tryAcquire(5000,TimeUnit.MILLISECONDS)){
    //                        test(threadNum);//需要并发控制的内容
    //                        semaphore.release(); // 释放许可
    //                    }
    //                } catch (Exception e) {
    //                    log.error("exception", e);
    //                }
    
    			});
    		}
    		threadPool.shutdown();
    		System.out.println("finish");
    	}
    
    	public static void test(int threadnum) throws InterruptedException {
    		Thread.sleep(1000);// 模拟请求的耗时操作
    		System.out.println("threadnum:" + threadnum);
    		Thread.sleep(1000);// 模拟请求的耗时操作
    	}
    }

    执行 acquire 方法阻塞,直到有一个许可证可以获得然后拿走一个许可证;每个 release 方法增加一个许可证,这可能会释放一个阻塞的acquire方法。然而,其实并没有实际的许可证这个对象,Semaphore只是维持了一个可获得许可证的数量。 Semaphore经常用于限制获取某种资源的线程数量。

    当然一次也可以一次拿取和释放多个许可,不过一般没有必要这样做:

    	semaphore.acquire(5);// 获取5个许可,所以可运行线程数量为20/5=4
    	test(threadnum);
    	semaphore.release(5);// 获取5个许可,所以可运行线程数量为20/5=4

    除了 acquire方法之外,另一个比较常用的与之对应的方法是tryAcquire方法,该方法如果获取不到许可就立即返回false。

    Semaphore 有两种模式,公平模式和非公平模式。

    • 公平模式: 调用acquire的顺序就是获取许可证的顺序,遵循FIFO;

    • 非公平模式: 抢占式的。

    Semaphore 对应的两个构造方法如下:

       public Semaphore(int permits) {
            sync = new NonfairSync(permits);
        }
    
        public Semaphore(int permits, boolean fair) {
            sync = fair ? new FairSync(permits) : new NonfairSync(permits);
        }

    这两个构造方法,都必须提供许可的数量,第二个构造方法可以指定是公平模式还是非公平模式,默认非公平模式。

    具体可看:https://blog.csdn.net/qq_19431333/article/details/70212663

    参照:https://blog.csdn.net/jesonjoke/article/details/80054133

    https://blog.csdn.net/xlgen157387/article/details/78218736

  • 相关阅读:
    N层电梯只停一层情况下,求所有人爬楼层数最少
    小组开发用户调研
    《哈利波特》买书最优惠算法
    团队开发——极速蜗牛
    林锐——软件工程思想后两章阅读笔记
    课堂练习之检测水军
    团队开发项目-----来用------典型用户与用户场景分析
    体验结对开发的乐趣(6)--(电梯调度问题)
    团队开发项目-----来用------用户需求调研报告
    课堂练习之最高折扣,最低优惠规划
  • 原文地址:https://www.cnblogs.com/baichendongyang/p/13235462.html
Copyright © 2011-2022 走看看