java 可伸缩阻塞队列实现
最近一年多写的最虐心的代码。必须好好复习java并发了。搞了一晚上终于测试都跑通过了,特此纪念,以资鼓励!
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.ArrayBlockingQueue;
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * 实现可调整大小的阻塞队列,支持数据迁移平衡reader,writer读取吸入速度,达到最大吞吐
- * @author hanjie
- *
- */
- public class RecordBuffer {
- public static final Record CLOSE_RECORD = new Record() {
- @Override
- public Object getColumnValue(String columnName) {
- // TODO Auto-generated method stub
- return null;
- }
- };
- public static final Record SWITCH_QUEUE_RECORD = new Record() {
- @Override
- public Object getColumnValue(String columnName) {
- // TODO Auto-generated method stub
- return null;
- }
- };
- public Lock switchingQueueLock = new ReentrantLock();
- public Condition readerSwitched = switchingQueueLock.newCondition();
- public Condition writerSwitched = switchingQueueLock.newCondition();
- public Condition switchFinished = switchingQueueLock.newCondition();
- public volatile boolean readerSwitchSuccess = true;
- public volatile boolean writerSwitchSuccess = true;
- public volatile boolean switchingQueue = false;
- public volatile boolean closed = false;
- private volatile ArrayBlockingQueue<Record> queue;
- private TaskCounter taskCounter;
- public RecordBuffer(TaskCounter taskCounter, int size) {
- this.queue = new ArrayBlockingQueue<Record>(size);
- this.taskCounter = taskCounter;
- }
- public void resize(int newSize) {
- try {
- if(closed){
- return;
- }
- switchingQueueLock.lock();
- try {
- //double check下,要不可能writer收到CLOSED_record已经 退出了。writerSwitched.await() 会hang住
- if(closed){
- return;
- }
- this.switchingQueue = true;
- ArrayBlockingQueue<Record> oldQueue = queue;
- queue = new ArrayBlockingQueue<Record>(newSize);
- this.readerSwitchSuccess = false;
- this.writerSwitchSuccess = false;
- //先拯救下writer,可能writer刚好阻塞到take上,失败也没关系,说明老队列不空,writer不会阻塞到take
- oldQueue.offer(SWITCH_QUEUE_RECORD);
- while (!writerSwitchSuccess) {
- writerSwitched.await();
- }
- //writer先切换队列,然后reader可能阻塞在最后一个put上,清空下老队列拯救reader,让它顺利醒来
- transferOldQueueRecordsToNewQueue(oldQueue);
- while (!readerSwitchSuccess) {
- readerSwitched.await();
- }
- //前面的清空,刚好碰到reader要put最后一个,非阻塞式清空动作就有残留最后一个put
- transferOldQueueRecordsToNewQueue(oldQueue);
- this.switchingQueue = false;
- this.switchFinished.signalAll();
- } finally {
- switchingQueueLock.unlock();
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new RuntimeException(e);
- }
- }
- private void transferOldQueueRecordsToNewQueue(ArrayBlockingQueue<Record> oldQueue)
- throws InterruptedException {
- List<Record> oldRecords = new ArrayList<Record>(oldQueue.size());
- Record record = null;
- while ((record = oldQueue.poll()) != null) {
- oldRecords.add(record);
- }
- // 转移老队列剩下的记录到新队列
- for (int i = 0; i < oldRecords.size(); i++) {
- queue.put(oldRecords.get(i));
- }
- }
- public void close() {
- this.closed = true;
- switchingQueueLock.lock();
- try {
- //如果正在切换队列, 等切换做完才能,发送最后一个CLOSE
- while (switchingQueue) {
- switchFinished.await();
- }
- this.queue.put(CLOSE_RECORD);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new RuntimeException(e);
- }
- finally{
- switchingQueueLock.unlock();
- }
- }
- public void put(Record record) {
- try {
- if (!queue.offer(record)) {
- taskCounter.incrBufferFullCount();
- if (!readerSwitchSuccess) {
- notifyReaderSwitchSuccess();
- }
- queue.put(record);
- }
- taskCounter.incrReadCount();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new RuntimeException(e);
- }
- }
- private void notifyReaderSwitchSuccess() {
- System.out.println("reader switch");
- switchingQueueLock.lock();
- try {
- readerSwitchSuccess = true;
- readerSwitched.signalAll();
- } finally {
- switchingQueueLock.unlock();
- }
- }
- public Record take() {
- try {
- Record record = queue.poll();
- //如果拿到了切换记录,则切换队列重试
- if(record == SWITCH_QUEUE_RECORD){
- if (!writerSwitchSuccess) {
- notifyWriterSwitchSuccess();
- }
- record = queue.poll();
- }
- if (record == null) {
- taskCounter.incrBufferEmptyCount();
- //调用take先检查是否正在切换,保证拿到新的队列
- if (!writerSwitchSuccess) {
- notifyWriterSwitchSuccess();
- }
- record = queue.take();
- //如果很不幸刚好在take阻塞时候,切换,只能发送一个切换记录将其唤醒
- if(record == SWITCH_QUEUE_RECORD){
- if (!writerSwitchSuccess) {
- notifyWriterSwitchSuccess();
- }
- record = queue.take();
- }
- }
- if (record == CLOSE_RECORD) {
- if (!writerSwitchSuccess) {
- notifyWriterSwitchSuccess();
- }
- return null;
- }
- taskCounter.incrWriteCount();
- return record;
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new RuntimeException(e);
- }
- }
- private void notifyWriterSwitchSuccess() {
- System.out.println("writer switch");
- switchingQueueLock.lock();
- try {
- writerSwitchSuccess = true;
- writerSwitched.signalAll();
- } finally {
- switchingQueueLock.unlock();
- }
- }
- }
java 可伸缩阻塞队列实现的更多相关文章
- Java多线程 阻塞队列和并发集合
转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的 ...
- Java集合--阻塞队列及各种实现的解析
阻塞队列(Blocking Queue) 一.队列的定义 说的阻塞队列,就先了解下什么是队列,队列也是一种特殊的线性表结构,在线性表的基础上加了一条限制:那就是一端入队列,一端出队列,且需要遵循FIF ...
- Java:阻塞队列
Java:阻塞队列 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 1. 概述 概念 队列 队列就可以想成是一个数组,从一头进入,一头出去,排队买饭 阻塞队列 B ...
- JAVA可阻塞队列-ArrayBlockingQueue
在前面的的文章,写了一个带有缓冲区的队列,是用JAVA的Lock下的Condition实现的,但是JAVA类中提供了这项功能,就是ArrayBlockingQueue, ArrayBlockingQu ...
- java 多线程阻塞队列 与 阻塞方法与和非阻塞方法
Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移 ...
- Java -- 使用阻塞队列(BlockingQueue)控制线程通信
BlockingQueeu接口是Queue的子接口,但是它的主要作用并不是作为容器,而是作为线程同步的工具. 特征: 当生产者线程试图向BlockingQueue中放入元素时,如果该队列已满,则该线程 ...
- Java并发--阻塞队列
在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...
- Java中阻塞队列的使用
http://blog.csdn.net/qq_35101189/article/details/56008342 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如 ...
- java并发阻塞队列
Java 并发编程利用 Condition 来实现阻塞队列 You are here: 开发&语言 - Java 文章 发布于 2017年06月26日 阅读 944 并发编程 什么是阻 ...
随机推荐
- CF 914F Substrings in a String——bitset处理匹配
题目:http://codeforces.com/contest/914/problem/F 可以对原字符串的每种字母开一个 bitset .第 i 位的 1 表示这种字母在第 i 位出现了. 考虑能 ...
- BaseAction编写:免去一些重复的代码,比如继承ActionSupport和实现ModelDriven接口
1.BaseAction package com.learning.crm.base; import java.lang.reflect.ParameterizedType; import java. ...
- Ice框架简介及Vs2013安装Ice 3.7.0步骤及实例
ICE是什么? ICE是ZEROC官网的开源通信协议产品,它的全称是:The Internet Communications Engine,翻译为中文是互联网通信引擎,是一个面向对象的中间件,支持C+ ...
- 杂项:Juice UI
ylbtech-杂项:Juice UI Juice UI是开源的 WebForms 控件集,是一个功能强大的框架,它可以给ASP .NET开发人员带来丰富的.可以作为易于使用的控件的jQuery UI ...
- MySQL数据库InnoDB存储引擎
MySQL数据库InnoDB存储引擎Log漫游 http://blog.163.com/zihuan_xuan/blog/static/1287942432012366293667/
- extends和implements区别
extends与implements的不同 1.在类的声明中,通过关键字extends来创建一个类的子类. 一个类通过关键字implements声明自己使用一个或者多个接口. extends 是继承某 ...
- 简单工厂法( Factory Method)
工厂方法 (Factory Method) Define an interface for creating an object ,but let subclasses decide which cl ...
- JavaScript中的坑
内容:关于JavaScript中的一些蛋疼的问题以及面试笔试中常见的一些坑爹套路总结 此部分内容持续总结完善中... 1.undefined和null的区别 null: Null类型,代表空值,代表一 ...
- Python序列化和反序列化vsJSON
# -*- coding: utf-8 -* """没有嵌套类的类 author: Jill usage: """ import json ...
- opencv3.1+contrib的配置大总结(配置了两天,遇到问题无数)
开门见山的说:别用opencv3.0,这个版本添加扩展库不怎么好,能不能成功我不敢说,我是试了无数次都不行!!! 我的配置:W7+64位+opencv3.1+Cmake3.7.2 下载 下载什么的大家 ...