DISRUPTOR初步介绍

队列底层一般分为三种:数组、链表、堆(不讨论)

基于数组线程安全的队列,典型是ArrayBlockingQueue,通过加锁的方式
来保证线程安全。基于链表线程安全队列分为LinkedBlockingQueue和
ConcurrentLinkedQueue。 前者通过加锁方式实现线程安全,后者通过
原子变量CAS来实现

通过不加锁的方式实现的队列都是无界的,而加锁的方式可以实现有界队列。
在稳定性要求高的系统中,为了防止生产者速度过快,导致内存溢出,只能
选择有界队列。同时为了减少Java垃圾回收堆系统性能的影响,尽量选择
array/heap数据结构,这些符合条件只有ArrayBlockingQueue

ArrayBlockingQueue在实际使用过程中,因加锁和伪共享(无法充分

使用缓存行特性的现象)等出现严重性能问题

Disruptor设计

环形数组结构

为了避免垃圾回收,采用数组而非链表。同时数组处理器的缓存机制更加友好

元素位置定位

数组长度2^n,通过位运算,加快定位的速度,下标采用递增的形式。index
是long类型

无锁设计

每个生产者活着消费者线程,会先申请可以操作的元素在数组中的位置,申请
到之后,直接在该位置写入或者读取数据

使用Disruptor每10秒向disruptor插入一个元素,消费者读取并打印示例

public class DisruptorMain {
public static void main(String[] args) throws Exception {

class Element {
private int value;

public int get() {
return value;
}

public void set(int value) {
this.value = value;
}
}

ThreadFactory threadFactory = new ThreadFactory() {
@Overrid
public Thread newThread(Runnable r) {
return new Thread(r, "thread-1")
}
};

EventFactory factory = new EveentFactory() {
@Overrid
public Element newInstance() {
return new Element();
}
};

EventHandler handler = new EventHandler() {
@Override
public void onEvent(Element element, long sequence, boolean endOfBatch) {
Systtem.out.println("element" + element.get());
}
};

BlockingWaitStrategy strategy = new BlockingWaitStrategy();
int bufferSize = 16;
Disruptor disruptor = new Disruptor(factory, bufferSize,
threadFactory, ProducerType.SINGLE, strategy);
disruptor.handleEventsWith(handler);
disruptor.start();

RingBuffer ringBuffer = disruptor.getRingBuffer();
for(int l = 0; true; l++) {
long sequence = ringBuffer.next();
try{
Element e = ringBuffer.get(sequence);
e.set(l);
}finally {
ringBuffer.publish(sequence);
}
Thread.sleep(10);
}
}
}

内容来源于美团技术博客

posted @ 2022-08-03 17:16  秋水秋色  阅读(99)  评论(0)    收藏  举报