分类: 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. ios基础篇(三十)—— AFNetworking的使用

    一.AFNetworking的创建 1.新建工程,命名为AFNDemo 2.导入AFNetworking.h AFNetworking文件下载:https://github.com/AFNetwork ...

  2. outline使用方法,outline与border的区别:

    在浏览器里,当鼠标点击或使用Tab键让一个链接或者一个radio获得焦点的时候,该元素将会被一个轮廓虚线框围绕.这个轮廓虚线框就是 outline . outline 能告诉用户那一个可以激发事件的h ...

  3. Mysql主数据库+备份数据库部署教程

    转:http://www.111cn.net/database/mysql/76450.htm 本文我们来讲讲Mysql主备如何部署,这里说的主是指Mysql主数据库,备是从数据库,备可以是多个,也可 ...

  4. RMAN 参数详解

    使用RMAN>show all;可以显示出RMAN 配置参数为: CONFIGURE RETENTION POLICY TO REDUNDANCY 1; # defaultCONFIGURE B ...

  5. Ubuntu 16.04 安装 .NET Core[转]

    upir@upir-Rev-1-0:~$ sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos ...

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

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

  7. 个人c语言编程风格总结

    总结一下我个人的编程风格及这样做的原因吧,其实是为了给实验室写一个统一的C语言编程规范才写的.首先声明,我下面提到的编程规范,是自己给自己定的,不是c语言里面规定的. 一件事情,做成和做好中间可能隔了 ...

  8. Selenium的延迟等待

    http://my.oschina.net/u/928852/blog/98885 Selenium的延迟等待分为 显式等待(Explicit Wait) & 隐式等待(Implicit Wa ...

  9. php截取utf-8中文字符串乱码的解决方法

    /** * PHP截取UTF-8字符串,解决半字符问题. * 英文.数字(半角)为1字节(8位),中文(全角)为2字节 * @return 取出的字符串, 当$len小于等于0时, 会返回整个字符串 ...

  10. 嵌入式Linux的调试技术

    本节我们研究嵌入式Linux的调试技术,对于复杂的Linux驱动及HAL等程序库,需要使用各种方法对其进行调试.刚开始讲了打印内核调试信息:printk,这个函数的用法与printf函数类似,只不过p ...