使用Lock来实现生产者和消费者问题

来源:互联网 发布:arraymap遍历数据 编辑:程序博客网 时间:2024/05/21 04:41

现在用Lock来实现它

复制代码
  1 package com.thread;  2   3 import java.util.LinkedList;  4 import java.util.concurrent.locks.Condition;  5 import java.util.concurrent.locks.Lock;  6 import java.util.concurrent.locks.ReentrantLock;  7   8   9 /** 10  * 使用Lock来实现生产者和消费者问题 11  *  12  * @author 刘玲 13  * 14  */ 15 public class ProducerConsumer { 16     public static void main(String[] args) { 17         Basket b = new Basket(); 18         Product p = new Product(b); 19         Consumer c = new Consumer(b); 20         Consumer c1 = new Consumer(b); 21         new Thread(p).start(); 22         new Thread(c).start(); 23         new Thread(c1).start(); 24     } 25 } 26 //馒头 27 class ManTou{ 28     int id; 29     public ManTou(int id) { 30         this.id = id; 31     } 32     @Override 33     public String toString() { 34         return "ManTou"+id; 35     } 36 } 37  38 //装馒头的篮子 39 class Basket{ 40     int max = 6; 41     LinkedList<ManTou> manTous = new LinkedList<ManTou>(); 42     Lock lock = new ReentrantLock(); //锁对象 43     Condition full = lock.newCondition();  //用来监控篮子是否满的Condition实例 44     Condition empty = lock.newCondition(); //用来监控篮子是否空的Condition实例 45     //往篮子里面放馒头 46     public void push(ManTou m){ 47         lock.lock(); 48         try { 49             while(max == manTous.size()){ 50                 System.out.println("篮子是满的,待会儿再生产..."); 51                 full.await(); 52             } 53             manTous.add(m); 54             empty.signal(); 55         } catch (InterruptedException e) { 56             e.printStackTrace(); 57         }finally{ 58             lock.unlock(); 59         } 60     } 61     //往篮子里面取馒头 62     public ManTou pop(){ 63         ManTou m = null; 64         lock.lock(); 65         try { 66             while(manTous.size() == 0){ 67                 System.out.println("篮子是空的,待会儿再吃..."); 68                 empty.await(); 69             } 70             m = manTous.removeFirst(); 71             full.signal(); 72         } catch (InterruptedException e) { 73             e.printStackTrace(); 74         }finally{ 75             lock.unlock(); 76             return m; 77         } 78     } 79 } 80 //生产者 81 class Product implements Runnable{ 82     Basket basket; 83     public Product(Basket basket) { 84         this.basket = basket; 85     } 86     public void run() { 87         for (int i = 0; i < 40; i++) { 88             ManTou m = new ManTou(i); 89             basket.push(m); 90             System.out.println("生产了"+m); 91             try { 92                 Thread.sleep((int)(Math.random()*2000)); 93             } catch (InterruptedException e) { 94                 e.printStackTrace(); 95             } 96              97         } 98     } 99 }100 101 //消费者102 class Consumer implements Runnable{103     Basket basket;104     public Consumer(Basket basket) {105         this.basket = basket;106     }107     public void run() {108         for (int i = 0; i < 20; i++) {109             try {110                 Thread.sleep((int)(Math.random()*2000));111             } catch (InterruptedException e) {112                 e.printStackTrace();113             }114             ManTou m = basket.pop();115             System.out.println("消费了"+m);116         }117     }118 }
复制代码

 附:synchronize与Lock的区别

一、synchronized和lock的用法区别
 
synchronized:在需要同步的对象中加入此控制,synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。
 
lock:需要显示指定起始位置和终止位置。一般使用ReentrantLock类做为锁,多个线程中必须要使用一个ReentrantLock类做为对象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。
 
用法区别比较简单,这里不赘述了,如果不懂的可以看看Java基本语法。
 
二、synchronized和lock性能区别
 
synchronized是托管给JVM执行的,而lock是java写的控制锁的代码。在Java1.5中,synchronize是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用Java提供的Lock对象,性能更高一些。但是到了Java1.6,发生了变化。synchronize在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在Java1.6上synchronize的性能并不比Lock差。官方也表示,他们也更支持synchronize,在未来的版本中还有优化余地。
 
说到这里,还是想提一下这2中机制的具体区别。据我所知,synchronized原始采用的是CPU悲观锁机制,即线程获得的是独占锁。独占锁意味着其他线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起CPU频繁的上下文切换导致效率很低。
 
而Lock用的是乐观锁方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁实现的机制就是CAS操作(Compare and Swap)。我们可以进一步研究ReentrantLock的源代码,会发现其中比较重要的获得锁的一个方法是compareAndSetState。这里其实就是调用的CPU提供的特殊指令。
 
现代的CPU提供了指令,可以自动更新共享数据,而且能够检测到其他线程的干扰,而 compareAndSet() 就用这些代替了锁定。这个算法称作非阻塞算法,意思是一个线程的失败或者挂起不应该影响其他线程的失败或挂起的算法。
 
我也只是了解到这一步,具体到CPU的算法如果感兴趣的读者还可以在查阅下,如果有更好的解释也可以给我留言,我也学习下。
 
三、synchronized和lock用途区别
 
synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
 
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小米6手机变卡了怎么办 微信绑定银行卡次数太多怎么办 银行卡绑定太多微信了怎么办 怎样给qq设密码怎么办 吃了心悦胶囊上火怎么办 qq暂时被冻结了怎么办 部落群审核未通过怎么办 qq被限制解封该怎么办 微信提现成功但没到账怎么办 拍拍贷登录不上怎么办 京东店铺出租保证金怎么办 所选地区无货怎么办 闲鱼七天没发货怎么办 续贷密码忘了怎么办 微店商家不发货怎么办 微店商家不退钱怎么办 维修车辆被拍违章停车怎么办 网贷申请平台太多怎么办 所在城市没有网店怎么办信用卡 拍拍贷不放款了怎么办 拍拍贷账号注销了怎么办 我在拍拍贷注销了怎么办 快贷逾期一年了怎么办 广州车牌买新车旧车怎么办 高尔夫旅行款被锁在车内怎么办 英雄联盟误删文件怎么办 拍拍贷换了号码怎么办 手机打开显示无法连接服务器怎么办 剑灵画面卡顿怎么办 cf被永久禁赛了怎么办 微信没有微游戏商店怎么办 游侠云盒下载慢怎么办2018 安卓手机玩网页游戏卡怎么办 safari点开什么都没有怎么办 康佳电视全网搜索打不开怎么办 脚被图钉扎了怎么办 电脑中毒了打不开软件怎么办 剑三程序不兼容怎么办 玩无主之地卡怎么办 平台老板跑路了怎么办 qq在苹果下载不了怎么办