一 从上一篇博客可以知道disruptor的工作图如下:

给人的印象就是RingBuffer是其核心,生产者向RingBuffer中写入元素,消费者从RingBuffer中消费元素。
RingBuffer其实就是一个环,首尾连接的一个环,只维护一个next()指向的下一个元素,当数据超过最大的限制的时候,其实就是一个覆盖操作,打个比方现在RingBuffer的长度为2^3=8,将下标从0到7的索引填满之后,下一个索引应该是8,这个时候其实只需要进行简单的取模操作即可,8%8就是覆盖第0个元素对象的数据,12的话就是12%8=4,就覆写索引下标为4的位置。
之前有说RingBuffer中槽的大小需要是2^n,这样是因为假如是2的n次方的话,进行操作完全可以用位运算,这是速度非常快的,比如: 8 >> 1 = 4 8 << 1 = 16
二 示例
下面以一个例子来模拟实现并行计算500个一亿求和的过程。
SingleSumEvent.java 这个类用来存储每个线程计算的值。
package com.lxj.disruptor2;public class SingleSumEvent { private String thread;
private long value; public String getThread() { return thread;
} public void setThread(String thread) { this.thread = thread;
} public long getValue() { return value;
} public void setValue(long value) { this.value = value;
}
public void calculate(long start , long end) { for(long i = start ; i <= end ; i++) {
value += i;
}
} @Override
public String toString() { return "SingleSumEvent [thread=" + thread + ", value=" + value + "]";
}
}MergerSumEvent.java 用来把每个生产者计算出来的值进行累加
package com.lxj.disruptor2;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import com.lmax.disruptor.WorkHandler;
public class MergerSumEvent implements WorkHandler<SingleSumEvent>{
//数值太大Long型会溢出
private volatile BigInteger sum = new BigInteger("0");
//原子操作
private volatile AtomicInteger count = new AtomicInteger(1);
//闭锁
private volatile CountDownLatch latch ;
public MergerSumEvent(CountDownLatch latch) {
this.latch = latch;
}
//每个SingleSumEvent 线程计算出来的值交给MergerSumEvent来累加
@Override
public void onEvent(SingleSumEvent singleSumEvent) throws Exception {
sum = sum.add(new BigInteger(singleSumEvent.getValue()+""));
System.out.println("线程"+singleSumEvent.getThread() +" " + count + "个一亿求和的结果为: " + sum );
count.incrementAndGet();
if(count.intValue() == 500) {
latch.countDown();
}
}
public BigInteger getSum() {
return sum;
}
}SumEventProducer.java 模拟外部磁盘数据或者网络传输过来的数据,并进行发布,是一个事件源,每次都触发,自己受到调用
package com.lxj.disruptor2;import com.lmax.disruptor.RingBuffer;public class SumEventProducer { private final RingBuffer<SingleSumEvent> ringBuffer;
public SumEventProducer(RingBuffer<SingleSumEvent> ringBuffer) { this.ringBuffer = ringBuffer;
} public void onData(long sum) { long sequence = ringBuffer.next(); try {
SingleSumEvent singleSumEvent = ringBuffer.get(sequence);
singleSumEvent.calculate(1, sum);
singleSumEvent.setValue(singleSumEvent.getValue());
singleSumEvent.setThread(Thread.currentThread().getName());
} finally { //发布事件
ringBuffer.publish(sequence);
}
}
}SumEventMain.java
package com.lxj.disruptor2;
import java.time.Duration;
import java.time.Instant;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import com.lmax.disruptor.AlertException;
import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.ExceptionHandler;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.Sequence;
import com.lmax.disruptor.SequenceBarrier;
import com.lmax.disruptor.TimeoutException;
import com.lmax.disruptor.WaitStrategy;
import com.lmax.disruptor.WorkerPool;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
public class SumEventMain {
public static void main(String[] args) throws Exception {
// 获取RungBuffer: ProducerType.MULTI: 多个生产者
RingBuffer<SingleSumEvent> ringBuffer = RingBuffer.create(ProducerType.MULTI, SingleSumEvent::new, (int) (Math.pow(2, 20)), new YieldingWaitStrategy());
SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();
final CountDownLatch latch = new CountDownLatch(1);
// 定义一个用于整合计算的消费者
MergerSumEvent mergerSumEvent = new MergerSumEvent(latch);
WorkerPool<SingleSumEvent> workerPool = new WorkerPool<SingleSumEvent>(ringBuffer, sequenceBarrier,
new IntEventExceptionHandler(), mergerSumEvent);
ringBuffer.addGatingSequences(workerPool.getWorkerSequences());
workerPool.start(Executors.newCachedThreadPool());
final SumEventProducer p = new SumEventProducer(ringBuffer);
Instant start = Instant.now();
for(int i = 0 ; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 5; j++) {
p.onData(100000000L);
}
}
}).start();
}
//等待所有任务完成
latch.await();
Instant end = Instant.now();
System.out.println("500个一亿(500*100000000)总共花费的时间: "+ Duration.between(start,end).toMillis() + " 秒,值为: " +mergerSumEvent.getSum());
workerPool.halt(); //通知事件(或者说消息)处理器 可以结束了(并不是马上结束!!!)
}
static class IntEventExceptionHandler implements ExceptionHandler<Object> {
public void handleEventException(Throwable ex, long sequence, Object event) {
}
public void handleOnStartException(Throwable ex) {
}
public void handleOnShutdownException(Throwable ex) {
}
}
}运行结果:
线程Thread-2 1个一亿求和的结果为: 5000000050000000 线程Thread-1 2个一亿求和的结果为: 10000000100000000 线程Thread-3 3个一亿求和的结果为: 15000000150000000 线程Thread-0 4个一亿求和的结果为: 20000000200000000 线程Thread-6 5个一亿求和的结果为: 25000000250000000 线程Thread-7 6个一亿求和的结果为: 30000000300000000 线程Thread-4 7个一亿求和的结果为: 35000000350000000 线程Thread-10 8个一亿求和的结果为: 40000000400000000 线程Thread-15 9个一亿求和的结果为: 45000000450000000 线程Thread-5 10个一亿求和的结果为: 50000000500000000 线程Thread-8 11个一亿求和的结果为: 55000000550000000 ........... 线程Thread-86 484个一亿求和的结果为: 2420000024200000000 线程Thread-55 485个一亿求和的结果为: 2425000024250000000 线程Thread-89 486个一亿求和的结果为: 2430000024300000000 线程Thread-41 487个一亿求和的结果为: 2435000024350000000 线程Thread-61 488个一亿求和的结果为: 2440000024400000000 线程Thread-77 489个一亿求和的结果为: 2445000024450000000 线程Thread-53 490个一亿求和的结果为: 2450000024500000000 线程Thread-77 491个一亿求和的结果为: 2455000024550000000 线程Thread-97 492个一亿求和的结果为: 2460000024600000000 线程Thread-69 493个一亿求和的结果为: 2465000024650000000 线程Thread-81 494个一亿求和的结果为: 2470000024700000000 线程Thread-93 495个一亿求和的结果为: 2475000024750000000 线程Thread-13 496个一亿求和的结果为: 2480000024800000000 线程Thread-85 497个一亿求和的结果为: 2485000024850000000 线程Thread-61 498个一亿求和的结果为: 2490000024900000000 线程Thread-69 499个一亿求和的结果为: 2495000024950000000 线程Thread-81 500个一亿求和的结果为: 2500000025000000000 500个一亿(500*(1亿求和))总共花费的时间: 13410 秒,值为: 2500000025000000000
cpu的利用率:


随时随地看视频