最近一年多写的最虐心的代码。必须好好复习java并发了。搞了一晚上终于测试都跑通过了,特此纪念,以资鼓励!

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import java.util.concurrent.ArrayBlockingQueue;
  4. import java.util.concurrent.locks.Condition;
  5. import java.util.concurrent.locks.Lock;
  6. import java.util.concurrent.locks.ReentrantLock;
  7.  
  8. /**
  9. * 实现可调整大小的阻塞队列,支持数据迁移平衡reader,writer读取吸入速度,达到最大吞吐
  10. * @author hanjie
  11. *
  12. */
  13. public class RecordBuffer {
  14.  
  15. public static final Record CLOSE_RECORD = new Record() {
  16.  
  17. @Override
  18. public Object getColumnValue(String columnName) {
  19. // TODO Auto-generated method stub
  20. return null;
  21. }
  22. };
  23.  
  24. public static final Record SWITCH_QUEUE_RECORD = new Record() {
  25.  
  26. @Override
  27. public Object getColumnValue(String columnName) {
  28. // TODO Auto-generated method stub
  29. return null;
  30. }
  31. };
  32.  
  33. public Lock switchingQueueLock = new ReentrantLock();
  34. public Condition readerSwitched = switchingQueueLock.newCondition();
  35. public Condition writerSwitched = switchingQueueLock.newCondition();
  36. public Condition switchFinished = switchingQueueLock.newCondition();
  37.  
  38. public volatile boolean readerSwitchSuccess = true;
  39. public volatile boolean writerSwitchSuccess = true;
  40. public volatile boolean switchingQueue = false;
  41. public volatile boolean closed = false;
  42. private volatile ArrayBlockingQueue<Record> queue;
  43. private TaskCounter taskCounter;
  44.  
  45. public RecordBuffer(TaskCounter taskCounter, int size) {
  46. this.queue = new ArrayBlockingQueue<Record>(size);
  47. this.taskCounter = taskCounter;
  48. }
  49.  
  50. public void resize(int newSize) {
  51. try {
  52.  
  53. if(closed){
  54. return;
  55. }
  56.  
  57. switchingQueueLock.lock();
  58. try {
  59. //double check下,要不可能writer收到CLOSED_record已经 退出了。writerSwitched.await() 会hang住
  60. if(closed){
  61. return;
  62. }
  63. this.switchingQueue = true;
  64.  
  65. ArrayBlockingQueue<Record> oldQueue = queue;
  66. queue = new ArrayBlockingQueue<Record>(newSize);
  67. this.readerSwitchSuccess = false;
  68. this.writerSwitchSuccess = false;
  69.  
  70. //先拯救下writer,可能writer刚好阻塞到take上,失败也没关系,说明老队列不空,writer不会阻塞到take
  71. oldQueue.offer(SWITCH_QUEUE_RECORD);
  72.  
  73. while (!writerSwitchSuccess) {
  74. writerSwitched.await();
  75. }
  76. //writer先切换队列,然后reader可能阻塞在最后一个put上,清空下老队列拯救reader,让它顺利醒来
  77. transferOldQueueRecordsToNewQueue(oldQueue);
  78.  
  79. while (!readerSwitchSuccess) {
  80. readerSwitched.await();
  81. }
  82. //前面的清空,刚好碰到reader要put最后一个,非阻塞式清空动作就有残留最后一个put
  83. transferOldQueueRecordsToNewQueue(oldQueue);
  84.  
  85. this.switchingQueue = false;
  86. this.switchFinished.signalAll();
  87.  
  88. } finally {
  89. switchingQueueLock.unlock();
  90. }
  91.  
  92. } catch (InterruptedException e) {
  93. Thread.currentThread().interrupt();
  94. throw new RuntimeException(e);
  95. }
  96. }
  97.  
  98. private void transferOldQueueRecordsToNewQueue(ArrayBlockingQueue<Record> oldQueue)
  99. throws InterruptedException {
  100. List<Record> oldRecords = new ArrayList<Record>(oldQueue.size());
  101. Record record = null;
  102. while ((record = oldQueue.poll()) != null) {
  103. oldRecords.add(record);
  104. }
  105. // 转移老队列剩下的记录到新队列
  106. for (int i = 0; i < oldRecords.size(); i++) {
  107. queue.put(oldRecords.get(i));
  108. }
  109. }
  110.  
  111. public void close() {
  112. this.closed = true;
  113. switchingQueueLock.lock();
  114. try {
  115. //如果正在切换队列, 等切换做完才能,发送最后一个CLOSE
  116. while (switchingQueue) {
  117. switchFinished.await();
  118. }
  119.  
  120. this.queue.put(CLOSE_RECORD);
  121. } catch (InterruptedException e) {
  122. Thread.currentThread().interrupt();
  123. throw new RuntimeException(e);
  124. }
  125. finally{
  126. switchingQueueLock.unlock();
  127. }
  128. }
  129.  
  130. public void put(Record record) {
  131. try {
  132.  
  133. if (!queue.offer(record)) {
  134. taskCounter.incrBufferFullCount();
  135. if (!readerSwitchSuccess) {
  136. notifyReaderSwitchSuccess();
  137. }
  138. queue.put(record);
  139. }
  140. taskCounter.incrReadCount();
  141. } catch (InterruptedException e) {
  142. Thread.currentThread().interrupt();
  143. throw new RuntimeException(e);
  144. }
  145. }
  146.  
  147. private void notifyReaderSwitchSuccess() {
  148. System.out.println("reader switch");
  149. switchingQueueLock.lock();
  150. try {
  151. readerSwitchSuccess = true;
  152. readerSwitched.signalAll();
  153. } finally {
  154. switchingQueueLock.unlock();
  155. }
  156. }
  157.  
  158. public Record take() {
  159. try {
  160.  
  161. Record record = queue.poll();
  162. //如果拿到了切换记录,则切换队列重试
  163. if(record == SWITCH_QUEUE_RECORD){
  164. if (!writerSwitchSuccess) {
  165. notifyWriterSwitchSuccess();
  166. }
  167. record = queue.poll();
  168. }
  169.  
  170. if (record == null) {
  171. taskCounter.incrBufferEmptyCount();
  172.  
  173. //调用take先检查是否正在切换,保证拿到新的队列
  174. if (!writerSwitchSuccess) {
  175. notifyWriterSwitchSuccess();
  176. }
  177. record = queue.take();
  178. //如果很不幸刚好在take阻塞时候,切换,只能发送一个切换记录将其唤醒
  179. if(record == SWITCH_QUEUE_RECORD){
  180. if (!writerSwitchSuccess) {
  181. notifyWriterSwitchSuccess();
  182. }
  183. record = queue.take();
  184. }
  185. }
  186. if (record == CLOSE_RECORD) {
  187. if (!writerSwitchSuccess) {
  188. notifyWriterSwitchSuccess();
  189. }
  190. return null;
  191. }
  192. taskCounter.incrWriteCount();
  193. return record;
  194. } catch (InterruptedException e) {
  195. Thread.currentThread().interrupt();
  196. throw new RuntimeException(e);
  197. }
  198. }
  199.  
  200. private void notifyWriterSwitchSuccess() {
  201.  
  202. System.out.println("writer switch");
  203. switchingQueueLock.lock();
  204. try {
  205. writerSwitchSuccess = true;
  206. writerSwitched.signalAll();
  207. } finally {
  208. switchingQueueLock.unlock();
  209. }
  210.  
  211. }
  212.  
  213. }

java 可伸缩阻塞队列实现的更多相关文章

  1. Java多线程 阻塞队列和并发集合

    转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的 ...

  2. Java集合--阻塞队列及各种实现的解析

    阻塞队列(Blocking Queue) 一.队列的定义 说的阻塞队列,就先了解下什么是队列,队列也是一种特殊的线性表结构,在线性表的基础上加了一条限制:那就是一端入队列,一端出队列,且需要遵循FIF ...

  3. Java:阻塞队列

    Java:阻塞队列 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 1. 概述 概念 队列 队列就可以想成是一个数组,从一头进入,一头出去,排队买饭 阻塞队列 B ...

  4. JAVA可阻塞队列-ArrayBlockingQueue

    在前面的的文章,写了一个带有缓冲区的队列,是用JAVA的Lock下的Condition实现的,但是JAVA类中提供了这项功能,就是ArrayBlockingQueue, ArrayBlockingQu ...

  5. java 多线程阻塞队列 与 阻塞方法与和非阻塞方法

    Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移 ...

  6. Java -- 使用阻塞队列(BlockingQueue)控制线程通信

    BlockingQueeu接口是Queue的子接口,但是它的主要作用并不是作为容器,而是作为线程同步的工具. 特征: 当生产者线程试图向BlockingQueue中放入元素时,如果该队列已满,则该线程 ...

  7. Java并发--阻塞队列

    在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...

  8. Java中阻塞队列的使用

    http://blog.csdn.net/qq_35101189/article/details/56008342 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如 ...

  9. java并发阻塞队列

    Java 并发编程利用 Condition 来实现阻塞队列 You are here:  开发&语言 - Java 文章 发布于 2017年06月26日  阅读 944 并发编程   什么是阻 ...

随机推荐

  1. CF 914F Substrings in a String——bitset处理匹配

    题目:http://codeforces.com/contest/914/problem/F 可以对原字符串的每种字母开一个 bitset .第 i 位的 1 表示这种字母在第 i 位出现了. 考虑能 ...

  2. BaseAction编写:免去一些重复的代码,比如继承ActionSupport和实现ModelDriven接口

    1.BaseAction package com.learning.crm.base; import java.lang.reflect.ParameterizedType; import java. ...

  3. Ice框架简介及Vs2013安装Ice 3.7.0步骤及实例

    ICE是什么? ICE是ZEROC官网的开源通信协议产品,它的全称是:The Internet Communications Engine,翻译为中文是互联网通信引擎,是一个面向对象的中间件,支持C+ ...

  4. 杂项:Juice UI

    ylbtech-杂项:Juice UI Juice UI是开源的 WebForms 控件集,是一个功能强大的框架,它可以给ASP .NET开发人员带来丰富的.可以作为易于使用的控件的jQuery UI ...

  5. MySQL数据库InnoDB存储引擎

    MySQL数据库InnoDB存储引擎Log漫游  http://blog.163.com/zihuan_xuan/blog/static/1287942432012366293667/

  6. extends和implements区别

    extends与implements的不同 1.在类的声明中,通过关键字extends来创建一个类的子类. 一个类通过关键字implements声明自己使用一个或者多个接口. extends 是继承某 ...

  7. 简单工厂法( Factory Method)

    工厂方法 (Factory Method) Define an interface for creating an object ,but let subclasses decide which cl ...

  8. JavaScript中的坑

    内容:关于JavaScript中的一些蛋疼的问题以及面试笔试中常见的一些坑爹套路总结 此部分内容持续总结完善中... 1.undefined和null的区别 null: Null类型,代表空值,代表一 ...

  9. Python序列化和反序列化vsJSON

    # -*- coding: utf-8 -* """没有嵌套类的类 author: Jill usage: """ import json ...

  10. opencv3.1+contrib的配置大总结(配置了两天,遇到问题无数)

    开门见山的说:别用opencv3.0,这个版本添加扩展库不怎么好,能不能成功我不敢说,我是试了无数次都不行!!! 我的配置:W7+64位+opencv3.1+Cmake3.7.2 下载 下载什么的大家 ...