分类: Java技术

     锁和信号量(Semaphore)是实现多线程同步的两种常用的手段。信号量需要初始化一个许可值,许可值可以大于0,也可以小于0,也可以等于0.

     如果大于0,表示,还有许可证可以发放,线程不会被阻塞;
     如果小于或者等于0,表示,没有许可证可以发放了,线程被阻塞住了。
     它有两个常用的操作,acquire()申请许可证,如果有,就可以获得,如果没有就等待了。
                         release(),归还许可证,保证循环使用。

     看一个例子,就会明白了,还是实现上次的那个生产者和消费者的例子。
     我们假设有一个篮子,最多可以放3个苹果,有多个人可以放苹果,也有多个人可以拿走苹果。
public class Apple {
    private String name;
    public Apple(String name){
       this. name= name;
    }
        @Override
        public String toString() {
               // TODO Auto-generated method stub
               return name ;
       }

}

public class Basket {
        private List bascket =new ArrayList(10);
       Semaphore mutex = new Semaphore(1);
       Semaphore isFull = new Semaphore(10);
       
       Semaphore isEmpty = new Semaphore(0);
       
        public void put(Apple app) throws InterruptedException{
               //大于0,就放行
               //acquire,就是减操作,如果小于0,就阻塞
               //release,就是加操作,如果大于0,就不会被阻塞
               isFull. acquire();
               try{
                      mutex. acquire();
                  bascket.add( app);
              }
               finally{
                      mutex.release();
                      isEmpty.release();
              }
       }
       
        public Apple take() throws InterruptedException{
              Apple app;
               isEmpty. acquire();
               try{
                      mutex. acquire();
                      app= bascket.remove(0);
              }
               finally{
                      mutex.release();
                      isFull.release();
              }
               return app ;
       }

}

//消费者
public class Consumer implements Runnable{
        private Basket bascket ;
        private String name ;
        public Consumer(Basket bascket ,String name ){
               this .bascket =bascket ;
               this .name =name ;
       }
        public void run(){
               while (true ){
                      try {
                           System. out .println(name +":consumer" +bascket .take());
                     } catch (InterruptedException e1) {
                            // TODO Auto-generated catch block
                            e1.printStackTrace();
                     }
                      try {
                           Thread. sleep(1000);
                     } catch (InterruptedException e ) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                     }
              }
       }

}

//生产者
public class Producer implements Runnable{
        private Basket bascket ;
        private String name ;
        public Producer(Basket bascket ,String name ){
               this .bascket =bascket ;
               this .name =name ;
       }
        public void run(){
              
               while (true ){
                      try {
                           System. out .println(name +"produce.." );
                            bascket. put( new Apple( "name" +new Random()));
                     } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                     }
                      try {
                           Thread. sleep(1000);
                     } catch (InterruptedException e ) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                     }
                     
              }
              
       }

}

public class TestDemo {
        public static void main(String args[]){
              Basket bascket= new Basket();
              Consumer c1= new Consumer(bascket ,"c1" );
              
              Producer p1= new Producer(bascket ,"p1" );
              Producer p2= new Producer(bascket ,"p2" );
              
               //线程池管理
              ExecutorService service = Executors. newCachedThreadPool();
               service.execute( c1);
               service.execute( p1);
               service.execute( p2);
       }
}

一定要注意,上面acquire的顺序,如果不正确,所有的线程就会被阻塞了。
信号量的实现原理会在源代码中进行分析。

JAVA并发框架之Semaphore实现生产者与消费者模型的更多相关文章

  1. Java并发框架AbstractQueuedSynchronizer(AQS)

    1.前言 本文介绍一下Java并发框架AQS,这是大神Doug Lea在JDK5的时候设计的一个抽象类,主要用于并发方面,功能强大.在新增的并发包中,很多工具类都能看到这个的影子,比如:CountDo ...

  2. 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.AQS框架简介 AQS诞生于Jdk1.5,在当时低效且功能单一的synchroni ...

  3. 深入理解Java并发框架AQS系列(四):共享锁(Shared Lock)

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock) 深入 ...

  4. Java 并发系列之十:java 并发框架(2个)

    1. Fork/Join框架 2. Executor框架 3. ThreadPoolExecutor 4. ScheduledThreadPoolExecutor 5. FutureTask 6. t ...

  5. 深入理解Java并发框架AQS系列(一):线程

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.概述 1.1.前言 重剑无锋,大巧不工 读j.u.c包下的源码,永远无法绕开的经典 ...

  6. 【java线程系列】java线程系列之线程间的交互wait()/notify()/notifyAll()及生产者与消费者模型

    关于线程,博主写过java线程详解基本上把java线程的基础知识都讲解到位了,但是那还远远不够,多线程的存在就是为了让多个线程去协作来完成某一具体任务,比如生产者与消费者模型,因此了解线程间的协作是非 ...

  7. python并发编程之守护进程、互斥锁以及生产者和消费者模型

    一.守护进程 主进程创建守护进程 守护进程其实就是'子进程' 一.守护进程内无法在开启子进程,否则会报错二.进程之间代码是相互独立的,主进程代码运行完毕,守护进程也会随机结束 守护进程简单实例: fr ...

  8. 生产者和消费者模型producer and consumer(单线程下实现高并发)

    #1.生产者和消费者模型producer and consumer modelimport timedef producer(): ret = [] for i in range(2): time.s ...

  9. Python 之并发编程之进程下(事件(Event())、队列(Queue)、生产者与消费者模型、JoinableQueue)

    八:事件(Event()) # 阻塞事件:    e = Event() 生成事件对象e    e.wait() 动态给程序加阻塞,程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值 ...

随机推荐

  1. 删除ORACLE的步骤

    1.关闭oracle所有的服务.可以在windows的服务管理器中关闭: 2.打开注册表:regedit 打开路径: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlS ...

  2. mac 安装mvn 失败

    安装过程遇到2个问题 1.java版本不对 2.Error: JAVA_HOME is not defined correctly. We cannot execute $/usr/libexec/j ...

  3. Java设计模式 工厂模式概念解析

    定义:工厂模式专门负责将大量有共同接口的类实例化.工厂模式可以动态决定将哪一个类实例化,而不必事先知道每次要实例化哪一个类. 三种形态: 简单工厂模式:又称静态工厂方法 工厂方法模式:又称多态性工厂模 ...

  4. Windows中一个22年的漏洞

     X Windows系统,今天作为世界各地的Linux桌面,已经存在超过20年了,仍然存在Bug.几天前Sysadmins为libXfont库提供了补丁,来对应新发现的已经在代码中存在了22年的特权升 ...

  5. Python中的下划线(译文)

    原文地址这篇文章讨论Python中下划线_的使用.跟Python中很多用法类似,下划线_的不同用法绝大部分(不全是)都是一种惯例约定. 单个下划线(_) 主要有三种情况: 1. 解释器中 _符号是指交 ...

  6. Haskell Tuple相关总结

    一.相关操作 zip:将两个List合并成一个元组序对的List. fst:返回元组序对第一个元素. snd:返回元组序对第二个元素. PS:元组序对是元组中只有两个元素的元组. 二.与List的比较 ...

  7. POJ 3463 有向图求次短路的长度及其方法数

    题目大意: 希望求出走出最短路的方法总数,如果次短路只比最短路小1,那也是可取的 输出总的方法数 这里n个点,每个点有最短和次短两种长度 这里采取的是dijkstra的思想,相当于我们可以不断找到更新 ...

  8. HDU2459 后缀数组+RMQ

    题目大意: 在原串中找到一个拥有连续相同子串最多的那个子串 比如dababababc中的abababab有4个连续的ab,是最多的 如果有同样多的输出字典序最小的那个 这里用后缀数组解决问题: 枚举连 ...

  9. Redis各类型应用场景

    Redis的六种特性 l ,重要消息的,然后工作线程可以选择按 ret = r.zincrby("login:login_times", 1, uid) //那么如何获得登录次数最 ...

  10. php 字符串转数组

    $str = "你好吗"; function str($str) {     $length = mb_strlen($str);     for ($i=0; $i<$le ...