zoukankan      html  css  js  c++  java
  • Java核心-多线程(7)-并发控制器-Semaphore信号量

    1. Semaphore是非常有用的一个多线程并发控制组件(Java还有CountDownLatch、CyclicBarrier、Exchanger多线程组件),它相当于是一个并发控制器,是用于管理信号量的。构造的时候传入可供管理的信号量的数值,这个数值就是控制并发数量的,就是同时能几个线程访问。我们需要控制并发的代码,执行前先通过acquire方法获取信号,执行后通过release归还信号 。每次acquire返回成功后,Semaphore可用的信号量就会减少一个,如果没有可用的信号,acquire调用就会阻塞,等待有release调用释放信号后,acquire才会得到信号并返回。
      private Semaphore semaphore = new Semaphore(3, true); #true时,使用公平策略,也就是是使用公平锁
      ps:注意这里信号量acquire方法和release方法是可以有参数的,表示获取/返还的信号量个数,如果不指定就是默认单个释放。

    2. Semaphore分为单值和多值两种

      • 单值的Semaphore管理的信号量只有1个,该信号量只能被1个,只能被一个线程所获得,意味着并发的代码只能被一个线程运行,这就相当于是一个互斥锁了。
      • 多值的Semaphore管理的信号量多余1个,主要用于控制并发数。
    3. 这种通过Semaphore控制并发并发数的方式和通过控制线程数来控制并发数的方式相比,粒度更小,因为Semaphore可以通过acquire方法和release方法来控制代码块的并发数。

    4. 在构造Semaphore对象时,同时可以控制并发时抢占锁的公平策略。在公平的锁上,线程按照他们发出请求的顺序获取锁,但在非公平锁上,则允许‘插队’:当一个线程请求非公平锁时,如果在发出请求的同时该锁变成可用状态,那么这个线程会跳过队列中所有的等待线程而获得锁。

    5. 非公平锁的效率高于公平锁,主要原因是,在恢复一个被挂起的线程与该线程真正运行之间存在着严重的延迟。
      ps.当持有锁的时间相对较长,应该使用公平锁。在这些情况下,插队带来的吞吐量提升可能不会出现。

    6. 使用示例,模仿上厕所排队的例子

     package common_test;
    import java.util.Random;
    import java.util.concurrent.*;
    
    public class SemaphoreTest {
    	
    	private Semaphore semaphore = new Semaphore(3, true);
    	private Random random = new Random();
    
    	
    	class Task implements Runnable{
    		private String id;
    		public Task(String id){
    			this.id = id;
    		}
    		public void run() {
    			try {
    				semaphore.acquire();
    				System.out.println("茅坑" + id + " 被占用了");
    				work();
    				System.out.println("茅坑" + id + " 空了");
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}finally{
    				semaphore.release();
    			}
    		}
    		
    		public void work(){
    			int worktime = random.nextInt(1000);
    	                System.out.println("茅坑  " + id + "使用了"+ worktime + "秒");
    	        try {
    	            Thread.sleep(worktime);
    	        } catch (InterruptedException e) {
    	            e.printStackTrace();
    	        }
    		}
    	}
    	public static void main(String[] args) {
    			SemaphoreTest semaphoreTest = new SemaphoreTest();
    			ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
    			newCachedThreadPool.submit(semaphoreTest.new Task(1+""));
    			newCachedThreadPool.submit(semaphoreTest.new Task(2+""));
    			newCachedThreadPool.submit(semaphoreTest.new Task(3+""));
    			newCachedThreadPool.submit(semaphoreTest.new Task(4+""));
    			newCachedThreadPool.submit(semaphoreTest.new Task(5+""));
    			newCachedThreadPool.submit(semaphoreTest.new Task(6+""));
    			newCachedThreadPool.submit(semaphoreTest.new Task(7+""));
    			newCachedThreadPool.shutdown();
    		}
    }
    
  • 相关阅读:
    【前端】Node.js学习笔记
    【前端】Web前端学习笔记【2】
    【Python】我的Python学习笔记【2】【using Python 3】
    【iOS】Foundation框架 学习笔记
    了解数据库对象
    对Bootstrap的粗略认识
    win10电脑突然开不了热点,怎么办
    excel 怎么将表中的空格都转变为0???
    cpno在数据库里面是什么意思??
    ·ps 的暂存盘空间不够
  • 原文地址:https://www.cnblogs.com/leeethan/p/10556217.html
Copyright © 2011-2022 走看看