每天一例多线程[day10]-----使用wait和notify模拟实现阻塞队列

 

  1. package com.jeff.base.conn009;

  2.  
  3. import java.util.LinkedList;

  4. import java.util.concurrent.TimeUnit;

  5. import java.util.concurrent.atomic.AtomicInteger;

  6.  
  7. /**

  8. * 使用wait和notify模拟阻塞队列

  9. * 当队列满时,put阻塞

  10. * 当队列空时,take阻塞

  11. *

  12. * @author jeffSheng

  13. *

  14. */

  15. public class MyQueue {

  16.  
  17. //1 需要一个承装元素的集合

  18. private LinkedList<Object> list = new LinkedList<Object>();

  19.  
  20. //2 需要一个计数器

  21. private AtomicInteger count = new AtomicInteger(0);

  22.  
  23. //3 需要制定上限和下限

  24. private final int minSize = 0;

  25.  
  26. private final int maxSize ;

  27.  
  28. //4 构造方法

  29. public MyQueue(int size){

  30. this.maxSize = size;

  31. }

  32.  
  33. //5 初始化一个对象 用于加锁

  34. private final Object lock = new Object();

  35.  
  36.  
  37. /**

  38. * put(anObject): 把anObject加到BlockingQueue里,

  39. * 如果BlockQueue没有空间,则调用此方法的线程被阻断,

  40. * 直到BlockingQueue里面有空间再继续.

  41. * @param obj

  42. */

  43. public void put(Object obj){

  44. synchronized (lock) {

  45. while(count.get() == this.maxSize){

  46. try {

  47. lock.wait();

  48. } catch (InterruptedException e) {

  49. e.printStackTrace();

  50. }

  51. }

  52. //1 加入元素

  53. list.add(obj);

  54. //2 计数器累加

  55. count.incrementAndGet();

  56. /**

  57. * 3 通知另外一个线程(唤醒)

  58. * 针对当队列为空时另外一个线程使用take方法中await阻塞,

  59. * 通知其可以取元素

  60. */

  61. lock.notify();

  62. System.out.println("新加入的元素为:" + obj);

  63. }

  64. }

  65.  
  66.  
  67. /**

  68. * take: 取走BlockingQueue里排在首位的对象,

  69. * 若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入.

  70. * @return

  71. */

  72. public Object take(){

  73. Object ret = null;

  74. synchronized (lock) {

  75. while(count.get() == this.minSize){

  76. try {

  77. lock.wait();

  78. } catch (InterruptedException e) {

  79. e.printStackTrace();

  80. }

  81. }

  82. //1 做移除元素操作

  83. ret = list.removeFirst();

  84. //2 计数器递减

  85. count.decrementAndGet();

  86. /**

  87. * 3 唤醒另外一个线程

  88. * 针对另外一个线程队列满而阻塞的情况

  89. */

  90. lock.notify();

  91. }

  92. return ret;

  93. }

  94.  
  95. public int getSize(){

  96. return this.count.get();

  97. }

  98.  
  99.  
  100. public static void main(String[] args) {

  101.  
  102. final MyQueue mq = new MyQueue(5);

  103. mq.put("a");

  104. mq.put("b");

  105. mq.put("c");

  106. mq.put("d");

  107. mq.put("e");

  108.  
  109. System.out.println("当前容器的长度:" + mq.getSize());

  110.  
  111. Thread t1 = new Thread(new Runnable() {

  112. @Override

  113. public void run() {

  114. mq.put("f");

  115. mq.put("g");

  116. }

  117. },"t1");

  118.  
  119. t1.start();

  120.  
  121. Thread t2 = new Thread(new Runnable() {

  122. @Override

  123. public void run() {

  124. Object o1 = mq.take();

  125. System.out.println("移除的元素为:" + o1);

  126. Object o2 = mq.take();

  127. System.out.println("移除的元素为:" + o2);

  128. }

  129. },"t2");

  130.  
  131. try {

  132. TimeUnit.SECONDS.sleep(2);

  133. } catch (InterruptedException e) {

  134. e.printStackTrace();

  135. }

  136. t2.start();

  137. }

  138. }


打印结果:

 
  1. 新加入的元素为:a

  2. 新加入的元素为:b

  3. 新加入的元素为:c

  4. 新加入的元素为:d

  5. 新加入的元素为:e

  6. 当前容器的长度:5

  7. 移除的元素为:a

  8. 移除的元素为:b

  9. 新加入的元素为:f

  10. 新加入的元素为:g

最后的队列元素:[c, d, e, f, g]

 

分析下执行过程:

定义一个最大长度为5的队列,并放入abcde5个元素,此时队列是满的,t1线程首先启动,尝试放置f和g两个元素进入队列,但是队列已满进入await阻塞状态,释放锁。t2线程创建后休眠一小会儿尝试移除队列中首位的元素,由于队列时满的[a,b,c,d,e]移除成功a,b后,t2使用notify唤醒t1,接着t1将f和g元素放入队列中.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值