一 从上一篇博客可以知道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的利用率:
三 从上面的例子,看看cpu的利用率,利用率非常高,从这里也可以看到disruptor的并行处理能力是非常强的。
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦