JAVA高性能并发插入+并发读取队列设计

为了应对审计中台的并发日志收集需求,文章介绍了如何设计一个支持高性能并发插入和读取的线程安全数据结构。由于普通的线程安全数据结构会影响性能,因此采用了类似ConcurrentHashMap的节点数组机制降低锁竞争,并应用双缓冲技术和哈希随机读取来提升并发读取效率,以避免业务系统受影响。
摘要由CSDN通过智能技术生成

背景:
1.公司需要开发统一审计中台,基本功能是收集其他各系统的操作日志,基本原理是提供SDK嵌入至其他业务系统,通过AOP注解截取方法入参出参上传至收集接口。
难点:
1.SDK通过AOP拦截方法,日志上传通过RPC调用会产生一次网络IO,势必会增加被注解修饰的方法的执行时间。而且网络环境波动,审计平台宕机等各种不稳定因素,会对被嵌入的系统产生致命影响。所以SDK必须要做异步日志上传,先在内存中缓存日志,然后由定时线程池取缓存中的日志上传。
2.因为是并发插入,故内存缓存使用的数据结构必须是线程安全的,目前jdk中的所有线程安全的数据结构除了ConcurrentHashMap(ConcurrentHashMap不能并发读取,会导致日志上传速度太慢故不采用)进行了性能优化,其他都是加锁串行,这样会导致所有被AOP拦截的方法全部串行化,方法执行时间会大大增加,这对业务系统的影响同样是致命的,所以需要自行设计一个支持高性能并发插入读取的线程安全的数据结构。
设计思想:
1.插入采用类似ConcurrentHashMap的node数组机制降低加锁串行概率,提高插入速度。
2.采用双缓冲技术思想使插入和读取数据分离,使读写互不影响。
3.对读取线程做hash随机读取数据,以支持并发读取。
最终代码如下:

import java.util.ArrayList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author yangjq
 * 双缓冲多队列并发读写,无序,不遵从先进先出原则
 */
public class ConcurrentDoubleBufferQueue {
   
  /**
   * 预估最大并发数
   */
  private int predict;
  /**
   * 每个队列容量
   */
  private int capacity;
  /**
   * 翻转间隔-毫秒
   */
  private long turnTime;
  /**
   * 读空时翻转阈值
   */
  private final int turnNum;
  /**
   * 默认预估最大并发数-200
   */
  private static final int DEFAULT_PREDICT = 200;
  /**
   * 默认每个队列容量-2000000
   */
  private static final int DEFAULT_CAPACITY = 2000000;
  /**
   * 默认翻转间隔-1秒
   */
  private static final long DEFAULT_TURNTIME = 1000;
  /**
   * 默认读空时翻转阈值-100个
   */
  private static final int DEFAULT_TURNNUM = 100;

  private volatile ArrayList<Integer> dataIndexs;

  private final ReentrantLock dataLock = new ReentrantLock();

  private final ReentrantLock takeLock = new ReentrantLock();

  private final Condition takeCondition = takeLock.newCondition();

  private volatile LinkedBlockingQueue<Object>[] writeArray;

  private volatile LinkedBlockingQueue<Object>[] readArray;

  private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);

  public ConcurrentDoubleBufferQueue() {
   
    this(DEFAULT_PREDICT, DEFAULT_CAPACITY, DEFAULT_TURNTIME, DEFAULT_TURNNUM);
  }

  /**
   * @param predict  预估最大并发数
   * @param capacity 每个队列容量
   * @param turnTime 翻转间隔-毫秒
   * @param turnNum  读空时翻转阈值
   */
  public ConcurrentDoubleBufferQueue(int predict, int capacity, long turnTime, int turnNum) {
   
    this.predict = predict;
    this.capacity = capacity;
    this.turnTime = turnTime;
    this.turnNum = turnNum;
    dataIndexs = new ArrayList<>();
    writeArray = new LinkedBlockingQueue[predict];
    for (int i = 0; i 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值