分类: 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. MySql学习(二) —— where / having / group by / order by / limit 简单查询

    注:该MySql系列博客仅为个人学习笔记. 这篇博客主要记录sql的五种子句查询语法! 一个重要的概念:将字段当做变量看,无论是条件,还是函数,或者查出来的字段. select五种子句 where 条 ...

  2. qt 编译问题总结

    1)使用make命令编译Qt原码时出现了 /usr/bin/ld: cannot find -lXrender 问题: /usr/bin/ld: cannot find -lXrender      ...

  3. redis命令全集(自用)

    1.连接操作相关的命令 quit:关闭连接(connection) auth:简单密码认证 2.对value操作的命令 exists(key):确认一个key是否存在 del(key):删除一个key ...

  4. 一生伏首拜阳明------<明朝那些事儿>

    一生伏首拜阳明. 王守仁,字伯安,别号阳明. 成化八年(1472),王守仁出生在浙江余姚,大凡成大事者往往出身贫寒,小小年纪就要上山砍柴,下海捞鱼,家里还有几个生病的亲属,每日以泪洗面.这差不多也是惯 ...

  5. Topcoder SRM558 1000 SurroundingGame

    题意:给定一个网格,每个网格有选取代价和占据收益.每个点被占据,需要满足以下两个条件至少一个条件:1.被选取  2.邻近方格都被选取(有公共边被称为邻近)  不一定要占据所有方格,求最大收益. 第一直 ...

  6. C# MD5加密

    public static string Encrypt(string txt) { System.Security.Cryptography.MD5CryptoServiceProvider md5 ...

  7. (转载)jQuery 1.6 源码学习(二)——core.js[2]之extend&ready方法

    上次分析了extend方法的实现,而紧接着extend方法后面调用了jQuery.extend()方法(core.js 359行),今天来看看究竟core.js里为jQuery对象扩展了哪些静态方法. ...

  8. 【初级】linux mkdir 命令详解及使用方法实战

    mkdir命令详解及使用方法实战 名称 MKDIR 是 make directories 的缩写 使用方法 mkdir [选项(如-p)] ...目录名称(及子目录注意用分隔符隔开)...    如使 ...

  9. MFC-01-Chapter01:Hello,MFC---1.3 第一个MFC程序(02)

    1.3.1 应用程序对象 MFC应用程序的核心就是基于CWinApp类的应用程序对象,CWinApp提供了消息循环来检索消息并将消息调度给应用程序的窗口.当包含头文件<afxwin.h>, ...

  10. iOS 8 以后 MKMapView 代理不执行问题

    因为ios8上,如果你使用了mapView,必须设置mapView的大小,必须把它添加显示在视图上. 可以将frame设为(0,0,0.1,0.1)