并发编程Disruptor入门
来源:互联网 发布:入侵服务器修改数据 编辑:程序博客网 时间:2024/05/16 01:00
获得Disruptor
可以通过Maven或者下载jar来安装Disruptor。只要把对应的jar放在Java classpath就可以了。
基本的事件生产和消费
我们从一个简单的例子开始学习Disruptor:生产者传递一个long类型的值给消费者,而消费者消费这个数据的方式仅仅是把它打印出来。首先声明一个Event来包含需要传递的数据
public class LongEvent { private long value; public long getValue() { return value; } public void setValue(long value) { this.value = value; } }
由于需要让Disruptor为我们创建事件,我们同时还声明了一个EventFactory来实例化Event对象
public class LongEventFactory implements EventFactory{ public Object newInstance() { return new LongEvent(); }}
我们还需要一个事件消费者,也就是一个事件处理器。这个事件处理器简单地把事件中存储的数据打印到终端
public class LongEventHandler implements EventHandler<LongEvent>{ public void onEvent(LongEvent longEvent, long l, boolean b) throws Exception { System.err.println("收到数据了:"+longEvent.getValue()); }}
事件都会有一个生成事件的源,这个例子中假设事件是由于磁盘IO或者network读取数据的时候触发的,事件源使用一个ByteBuffer来模拟它接受到的数据,也就是说,事件源会在IO读取到一部分数据的时候触发事件(触发事件不是自动的,程序员需要在读取到数据的时候自己触发事件并发布)
public class LongEventProducer { private final RingBuffer<LongEvent> ringBuffer; public LongEventProducer(RingBuffer<LongEvent> ringBuffer) { this.ringBuffer = ringBuffer; } /** * onData用来发布事件,每调用一次就发布一次事件事件 它的参数会通过事件传递给消费者 * * @param b */ public void onData(ByteBuffer b) { // 可以把ringBuffer看做一个事件队列,那么next就是得到下面一个事件槽 long sequence = ringBuffer.next(); try { // 用上面的索引取出一个空的事件用于填充 LongEvent event = ringBuffer.get(sequence); // for the sequence event.setValue(b.getLong(0)); } finally { // 发布事件 ringBuffer.publish(sequence); } }}
很明显的是:当用一个简单队列来发布事件的时候会牵涉更多的细节,这是因为事件对象还需要预先创建。发布事件最少需要两步:获取下一个事件槽并发布事件(发布事件的时候要使用try/finnally保证事件一定会被发布)。如果我们使用RingBuffer.next()获取一个事件槽,那么一定要发布对应的事件。如果不能发布事件,那么就会引起Disruptor状态的混乱。尤其是在多个事件生产者的情况下会导致事件消费者失速,从而不得不重启应用才能会恢复。
Disruptor 3.0提供了lambda式的API。这样可以把一些复杂的操作放在Ring Buffer,所以在Disruptor3.0以后的版本最好使用Event Publisher或者Event Translator来发布事件
public class LongEventProducerWithTranslator { // 一个translator可以看做一个事件初始化器,publicEvent方法会调用它填充Event private static final EventTranslatorOneArg<LongEvent, ByteBuffer> TRANSLATOR = new EventTranslatorOneArg<LongEvent, ByteBuffer>() { public void translateTo(LongEvent event, long sequence, ByteBuffer b) { event.setValue(b.getLong(0)); } }; private final RingBuffer<LongEvent> ringBuffer; public LongEventProducerWithTranslator(RingBuffer<LongEvent> ringBuffer) { this.ringBuffer = ringBuffer; } public void onData(ByteBuffer b) { ringBuffer.publishEvent(TRANSLATOR, b); }}
上面写法的另一个好处是,Translator可以分离出来并且更加容易单元测试。Disruptor提供了不同的接口(EventTranslator, EventTranslatorOneArg, EventTranslatorTwoArg, 等等)去产生一个Translator对象。很明显,Translator中方法的参数是通过RingBuffer来传递的。
最后一步就是把所有的代码组合起来完成一个完整的事件处理系统。Disruptor在这方面做了简化,使用了DSL风格的代码(其实就是按照直观的写法,不太能算得上真正的DSL)。虽然DSL的写法比较简单,但是并没有提供所有的选项。如果依靠DSL已经可以处理大部分情况了。
public class LongEventMain { public static void main(String[] args) throws InterruptedException { // Executor that will be used to construct new threads for consumers Executor executor = Executors.newCachedThreadPool(); // The factory for the event LongEventFactory factory = new LongEventFactory(); // Specify the size of the ring buffer, must be power of 2. int bufferSize = 1024; // Construct the Disruptor Disruptor<LongEvent> disruptor = new Disruptor<LongEvent>(factory, bufferSize, executor); // Connect the handler disruptor.handleEventsWith(new LongEventHandler()); // Start the Disruptor, starts all threads running disruptor.start(); // Get the ring buffer from the Disruptor to be used for publishing. RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer(); LongEventProducer producer = new LongEventProducer(ringBuffer); ByteBuffer b = ByteBuffer.allocate(8); for (long l = 0; l<100; l++) { b.putLong(0, l); producer.onData(b); //Thread.sleep(1000); } disruptor.shutdown(); }}
得到结果:
收到数据了:0收到数据了:1收到数据了:2收到数据了:3收到数据了:4收到数据了:5收到数据了:6收到数据了:7收到数据了:8收到数据了:9收到数据了:10收到数据了:11收到数据了:12收到数据了:13收到数据了:14收到数据了:15收到数据了:16收到数据了:17收到数据了:18收到数据了:19收到数据了:20收到数据了:21收到数据了:22收到数据了:23收到数据了:24收到数据了:25收到数据了:26收到数据了:27收到数据了:28收到数据了:29收到数据了:30收到数据了:31收到数据了:32收到数据了:33收到数据了:34收到数据了:35收到数据了:36收到数据了:37收到数据了:38收到数据了:39收到数据了:40收到数据了:41收到数据了:42收到数据了:43收到数据了:44收到数据了:45收到数据了:46收到数据了:47收到数据了:48收到数据了:49收到数据了:50收到数据了:51收到数据了:52收到数据了:53收到数据了:54收到数据了:55收到数据了:56收到数据了:57收到数据了:58收到数据了:59收到数据了:60收到数据了:61收到数据了:62收到数据了:63收到数据了:64收到数据了:65收到数据了:66收到数据了:67收到数据了:68收到数据了:69收到数据了:70收到数据了:71收到数据了:72收到数据了:73收到数据了:74收到数据了:75收到数据了:76收到数据了:77收到数据了:78收到数据了:79收到数据了:80收到数据了:81收到数据了:82收到数据了:83收到数据了:84收到数据了:85收到数据了:86收到数据了:87收到数据了:88收到数据了:89收到数据了:90收到数据了:91收到数据了:92收到数据了:93收到数据了:94收到数据了:95收到数据了:96收到数据了:97收到数据了:98收到数据了:99
- 并发编程Disruptor入门
- Disruptor并发框架入门
- disruptor - 并发编程框架
- 并发编程框架 Disruptor
- disruptor 并发编程
- 互联网架构(6):并发编程--Disruptor并发框架
- 架构师入门笔记七 并发框架Disruptor快速入门
- Disruptor入门
- Disruptor入门
- Disruptor入门
- Disruptor入门
- Disruptor入门
- Disruptor入门
- Disruptor入门
- 架构师入门笔记八 并发框架Disruptor场景应用
- 并发编程:Disruptor为什么这么快,锁的缺点
- 并发框架Disruptor译文
- 并发框架Disruptor译文
- 获取所有文件夹中所有文件url(不包括文件夹)
- 加密机变更CheckList
- jQuery获取多种input值的方法
- 第1.2章 web基础
- 关闭windows服务器的“windows update”功能
- 并发编程Disruptor入门
- Linux命令——crontab
- java poi 生成多个sheet(表格导出)
- redis简单使用(勿看)
- 引导页-ViewFlipper与手势
- AndroidMainfest.xml详解——<compatible-screens>
- Atom
- STS (Spring tools stuite)使用Gradle创建Spring Boot整合templates做网站示例
- mongoDB 3.0 安全权限访问