├── settings.gradle ├── docs └── Disruptor.docx ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src ├── main │ └── java │ │ └── com │ │ └── lmax │ │ └── disruptor │ │ ├── TimeoutHandler.java │ │ ├── EventSequencer.java │ │ ├── BatchStartAware.java │ │ ├── TimeoutException.java │ │ ├── EventReleaser.java │ │ ├── EventReleaseAware.java │ │ ├── DataProvider.java │ │ ├── dsl │ │ ├── EventProcessorFactory.java │ │ ├── ExceptionHandlerWrapper.java │ │ ├── ProducerType.java │ │ ├── ConsumerInfo.java │ │ ├── WorkerPoolInfo.java │ │ ├── ExceptionHandlerSetting.java │ │ └── BasicExecutor.java │ │ ├── util │ │ ├── DaemonThreadFactory.java │ │ └── ThreadHints.java │ │ ├── Cursored.java │ │ ├── EventFactory.java │ │ ├── EventTranslatorVararg.java │ │ ├── LifecycleAware.java │ │ ├── EventTranslatorOneArg.java │ │ ├── EventTranslatorTwoArg.java │ │ ├── WorkHandler.java │ │ ├── InsufficientCapacityException.java │ │ ├── EventTranslatorThreeArg.java │ │ ├── EventTranslator.java │ │ ├── AlertException.java │ │ ├── IgnoreExceptionHandler.java │ │ ├── BusySpinWaitStrategy.java │ │ ├── SequenceReportingEventHandler.java │ │ ├── ExceptionHandler.java │ │ ├── FatalExceptionHandler.java │ │ ├── EventProcessor.java │ │ ├── YieldingWaitStrategy.java │ │ ├── FixedSequenceGroup.java │ │ ├── NoOpEventProcessor.java │ │ ├── EventHandler.java │ │ ├── TimeoutBlockingWaitStrategy.java │ │ ├── AggregateEventHandler.java │ │ └── BlockingWaitStrategy.java ├── perftest │ └── java │ │ └── com │ │ └── lmax │ │ └── disruptor │ │ ├── immutable │ │ ├── EventAccessor.java │ │ ├── Constants.java │ │ ├── SimpleEventHandler.java │ │ ├── EventHolder.java │ │ ├── EventHolderHandler.java │ │ ├── SimpleEvent.java │ │ ├── CustomPerformanceTest.java │ │ ├── SimplePerformanceTest.java │ │ └── CustomRingBuffer.java │ │ ├── support │ │ ├── FunctionStep.java │ │ ├── FizzBuzzStep.java │ │ ├── ValueAdditionWorkHandler.java │ │ ├── ValueEvent.java │ │ ├── EventCountingWorkHandler.java │ │ ├── PerfTestUtil.java │ │ ├── Operation.java │ │ ├── ValueAdditionEventHandler.java │ │ ├── EventCountingAndReleasingWorkHandler.java │ │ ├── LongArrayEventHandler.java │ │ ├── ValueQueuePublisher.java │ │ ├── FizzBuzzEvent.java │ │ ├── EventCountingQueueProcessor.java │ │ ├── ValueMutationEventHandler.java │ │ ├── ValuePublisher.java │ │ ├── FunctionEvent.java │ │ ├── LongArrayPublisher.java │ │ ├── ValueBatchPublisher.java │ │ ├── ValueAdditionQueueProcessor.java │ │ ├── FunctionEventHandler.java │ │ ├── ValueMutationQueueProcessor.java │ │ └── FizzBuzzEventHandler.java │ │ ├── primitive │ │ └── LongRingBuffer.java │ │ ├── AbstractPerfTestDisruptor.java │ │ └── AbstractPerfTestQueue.java └── test │ └── java │ └── com │ └── lmax │ └── disruptor │ ├── support │ ├── DummyWaitStrategy.java │ ├── DummyEventHandler.java │ ├── TestEvent.java │ ├── LongEvent.java │ ├── DummyEventProcessor.java │ ├── DummySequenceBarrier.java │ ├── WaitStrategyTestUtil.java │ ├── SequenceUpdater.java │ ├── TestWaiter.java │ └── StubEvent.java │ ├── SingleProducerSequencerTest.java │ ├── example │ ├── NamedEventHandler.java │ ├── KeyedBatching.java │ ├── SequentialThreeConsumers.java │ ├── WaitForShutdown.java │ ├── HandleExceptionOnTranslate.java │ ├── PullWithPoller.java │ ├── ThreeToOneDisruptor.java │ └── DynamiclyAddHandler.java │ ├── SleepingWaitStrategyTest.java │ ├── BusySpinWaitStrategyTest.java │ ├── YieldingWaitStrategyTest.java │ ├── dsl │ └── stubs │ │ ├── TestWorkHandler.java │ │ ├── SleepingEventHandler.java │ │ ├── EventHandlerStub.java │ │ ├── EvilEqualsEventHandler.java │ │ ├── ExceptionThrowingEventHandler.java │ │ ├── StubExceptionHandler.java │ │ ├── StubPublisher.java │ │ ├── DelayedEventHandler.java │ │ └── StubThreadFactory.java │ ├── IgnoreExceptionHandlerTest.java │ ├── TimeoutBlockingWaitStrategyTest.java │ ├── LiteTimeoutBlockingWaitStrategyTest.java │ ├── FixedSequenceGroupTest.java │ ├── util │ ├── PaddedLong.java │ ├── MutableLong.java │ └── UtilTest.java │ ├── FatalExceptionHandlerTest.java │ ├── MultiProducerSequencerTest.java │ ├── EventTranslatorTest.java │ ├── RingBufferEventMatcher.java │ ├── PhasedBackoffWaitStrategyTest.java │ ├── EventPublisherTest.java │ ├── WorkerPoolTest.java │ ├── LifecycleAwareTest.java │ ├── ShutdownOnFatalExceptionTest.java │ └── EventPollerTest.java ├── .gitignore ├── config └── checkstyle │ └── suppress.xml ├── runme.sh ├── runoffheap.sh └── gradlew.bat /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'disruptor' 2 | -------------------------------------------------------------------------------- /docs/Disruptor.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hl845740757/disruptor-translation/HEAD/docs/Disruptor.docx -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hl845740757/disruptor-translation/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/TimeoutHandler.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | public interface TimeoutHandler 4 | { 5 | void onTimeout(long sequence) throws Exception; 6 | } 7 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/immutable/EventAccessor.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.immutable; 2 | 3 | public interface EventAccessor 4 | { 5 | T take(long sequence); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventSequencer.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | /** 4 | * 事件序号生成器 5 | * @param 6 | */ 7 | public interface EventSequencer extends DataProvider, Sequenced 8 | { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /build 3 | /.gradle 4 | /out 5 | .DS_Store 6 | *~ 7 | classes 8 | code 9 | templib 10 | SConstruct 11 | .*dblite 12 | pom.xml 13 | .project 14 | .classpath 15 | .settings 16 | .idea 17 | *.iml 18 | *.ipr 19 | *.iws 20 | *-gc.log 21 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/immutable/Constants.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.immutable; 2 | 3 | public class Constants 4 | { 5 | public static final long ITERATIONS = 1000 * 1000 * 100L; 6 | public static final int SIZE = 1 << 20; 7 | } 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Mar 20 19:48:04 NZDT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-all.zip 7 | -------------------------------------------------------------------------------- /config/checkstyle/suppress.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/immutable/SimpleEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.immutable; 2 | 3 | import com.lmax.disruptor.EventHandler; 4 | 5 | public class SimpleEventHandler implements EventHandler 6 | { 7 | public long counter; 8 | 9 | @Override 10 | public void onEvent(SimpleEvent arg0, long arg1, boolean arg2) throws Exception 11 | { 12 | counter += arg0.getCounter(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/BatchStartAware.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | /** 4 | * 批量事件处理通知(感知) 5 | * 如果你的EventHandler实现了该接口,那么当批处理开始时,你会收到通知 6 | * Implement this interface in your {@link EventHandler} to be notified when a thread for the 7 | * {@link BatchEventProcessor} start process events. 8 | */ 9 | public interface BatchStartAware 10 | { 11 | /** 12 | * 批处理开始 13 | * @param batchSize 本批次事件个数 14 | */ 15 | void onBatchStart(long batchSize); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/TimeoutException.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | @SuppressWarnings("serial") 4 | public final class TimeoutException extends Exception 5 | { 6 | public static final TimeoutException INSTANCE = new TimeoutException(); 7 | 8 | private TimeoutException() 9 | { 10 | // Singleton 11 | } 12 | 13 | @Override 14 | public synchronized Throwable fillInStackTrace() 15 | { 16 | return this; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/immutable/EventHolder.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.immutable; 2 | 3 | import com.lmax.disruptor.EventFactory; 4 | 5 | public class EventHolder 6 | { 7 | 8 | public static final EventFactory FACTORY = new EventFactory() 9 | { 10 | @Override 11 | public EventHolder newInstance() 12 | { 13 | return new EventHolder(); 14 | } 15 | }; 16 | 17 | public SimpleEvent event; 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/support/DummyWaitStrategy.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.support; 2 | 3 | import com.lmax.disruptor.*; 4 | 5 | public class DummyWaitStrategy implements WaitStrategy 6 | { 7 | public int signalAllWhenBlockingCalls = 0; 8 | 9 | @Override 10 | public long waitFor( 11 | long sequence, Sequence cursor, Sequence dependentSequence, SequenceBarrier barrier) 12 | throws AlertException, InterruptedException, TimeoutException 13 | { 14 | return 0; 15 | } 16 | 17 | @Override 18 | public void signalAllWhenBlocking() 19 | { 20 | signalAllWhenBlockingCalls++; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/immutable/EventHolderHandler.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.immutable; 2 | 3 | import com.lmax.disruptor.EventHandler; 4 | 5 | public class EventHolderHandler implements EventHandler 6 | { 7 | private final EventHandler delegate; 8 | 9 | public EventHolderHandler(EventHandler delegate) 10 | { 11 | this.delegate = delegate; 12 | } 13 | 14 | @Override 15 | public void onEvent(EventHolder holder, long sequence, boolean endOfBatch) throws Exception 16 | { 17 | delegate.onEvent(holder.event, sequence, endOfBatch); 18 | holder.event = null; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/immutable/SimpleEvent.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.immutable; 2 | 3 | public class SimpleEvent 4 | { 5 | private final long id; 6 | private final long v1; 7 | private final long v2; 8 | private final long v3; 9 | 10 | public SimpleEvent(long id, long v1, long v2, long v3) 11 | { 12 | this.id = id; 13 | this.v1 = v1; 14 | this.v2 = v2; 15 | this.v3 = v3; 16 | } 17 | 18 | public long getCounter() 19 | { 20 | return v1; 21 | } 22 | 23 | @Override 24 | public String toString() 25 | { 26 | return "SimpleEvent [id=" + id + ", v1=" + v1 + ", v2=" + v2 + ", v3=" + v3 + "]"; 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventReleaser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | public interface EventReleaser 19 | { 20 | void release(); 21 | } 22 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/FunctionStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | public enum FunctionStep 19 | { 20 | ONE, 21 | TWO, 22 | THREE 23 | } 24 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/FizzBuzzStep.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | public enum FizzBuzzStep 19 | { 20 | FIZZ, 21 | BUZZ, 22 | FIZZ_BUZZ, 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/support/DummyEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.support; 2 | 3 | import com.lmax.disruptor.EventHandler; 4 | import com.lmax.disruptor.LifecycleAware; 5 | 6 | public class DummyEventHandler implements EventHandler, LifecycleAware 7 | { 8 | public int startCalls = 0; 9 | public int shutdownCalls = 0; 10 | public T lastEvent; 11 | public long lastSequence; 12 | 13 | @Override 14 | public void onStart() 15 | { 16 | startCalls++; 17 | } 18 | 19 | @Override 20 | public void onShutdown() 21 | { 22 | shutdownCalls++; 23 | } 24 | 25 | @Override 26 | public void onEvent(T event, long sequence, boolean endOfBatch) throws Exception 27 | { 28 | lastEvent = event; 29 | lastSequence = sequence; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventReleaseAware.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | public interface EventReleaseAware 19 | { 20 | void setEventReleaser(EventReleaser eventReleaser); 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/SingleProducerSequencerTest.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.hamcrest.core.IsNot.not; 6 | import static org.junit.Assert.*; 7 | 8 | public class SingleProducerSequencerTest 9 | { 10 | @Test 11 | public void shouldNotUpdateCursorDuringHasAvailableCapacity() throws Exception 12 | { 13 | SingleProducerSequencer sequencer = new SingleProducerSequencer(16, new BusySpinWaitStrategy()); 14 | 15 | for (int i = 0; i < 32; i++) 16 | { 17 | long next = sequencer.next(); 18 | assertThat(sequencer.cursor.get(), not(next)); 19 | 20 | sequencer.hasAvailableCapacity(13); 21 | assertThat(sequencer.cursor.get(), not(next)); 22 | 23 | sequencer.publish(next); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /runme.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm *-gc.log 4 | 5 | ARGS="$JAVA_HOME/bin/java -mx128m" 6 | GCARGS="-verbose:gc -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+UseParNewGC -XX:+UseConcMarkSweepGC" 7 | CPATH="-cp build/classes/main:build/classes/perf:templib/*.jar" 8 | 9 | echo "Running Simple..." 10 | time $ARGS $GCARGS -Xloggc:simple-gc.log $CPATH com.lmax.disruptor.immutable.SimplePerformanceTest 11 | echo "Done" 12 | 13 | grep 'stopped:' simple-gc.log | sed 's/.*stopped: \([0-9.]*\) seconds/\1/' | sort -n | awk '{ printf "%1.3f\n", $1 }' | (echo " Count Millis" ; uniq -c ) 14 | 15 | echo "Running Custom..." 16 | time $ARGS $GCARGS -Xloggc:custom-gc.log $CPATH com.lmax.disruptor.immutable.CustomPerformanceTest 17 | echo "Done" 18 | 19 | grep 'stopped:' custom-gc.log | sed 's/.*stopped: \([0-9.]*\) seconds/\1/' | sort -n | awk '{ printf "%1.3f\n", $1 }' | (echo " Count Millis" ; uniq -c ) 20 | 21 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/DataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 数据提供者,目前就是 {@link RingBuffer} 20 | * @param 21 | */ 22 | public interface DataProvider 23 | { 24 | /** 25 | * 根据指定序号获取data 26 | */ 27 | T get(long sequence); 28 | } 29 | -------------------------------------------------------------------------------- /runoffheap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm *-gc.log 4 | 5 | ARGS="$JAVA_HOME/bin/java -mx1g" 6 | GCARGS="-verbose:gc -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:MaxDirectMemorySize=1g" 7 | CPATH="-cp build/classes/main:build/classes/perf:templib/*.jar" 8 | BIN="perf stat -e L1-dcache-loads -e L1-dcache-load-misses -e LLC-loads -e LLC-load-misses -e dTLB-loads -e dTLB-load-misses" 9 | 10 | echo "Running OffHeap..." 11 | $BIN $ARGS $GCARGS -Xloggc:simple-gc.log $CPATH com.lmax.disruptor.offheap.OneToOneOffHeapThroughputTest 12 | echo "Done" 13 | 14 | echo "Running OnHeap..." 15 | $BIN $ARGS $GCARGS -Xloggc:custom-gc.log $CPATH com.lmax.disruptor.offheap.OneToOneOnHeapThroughputTest 16 | echo "Done" 17 | 18 | echo "Running Sliced OnHeap..." 19 | $BIN $ARGS $GCARGS -Xloggc:custom-gc.log $CPATH -Dsliced=true com.lmax.disruptor.offheap.OneToOneOnHeapThroughputTest 20 | echo "Done" 21 | 22 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/example/NamedEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.example; 2 | 3 | import com.lmax.disruptor.EventHandler; 4 | import com.lmax.disruptor.LifecycleAware; 5 | 6 | public class NamedEventHandler implements EventHandler, LifecycleAware 7 | { 8 | private String oldName; 9 | private final String name; 10 | 11 | public NamedEventHandler(final String name) 12 | { 13 | this.name = name; 14 | } 15 | 16 | @Override 17 | public void onEvent(final T event, final long sequence, final boolean endOfBatch) throws Exception 18 | { 19 | } 20 | 21 | @Override 22 | public void onStart() 23 | { 24 | final Thread currentThread = Thread.currentThread(); 25 | oldName = currentThread.getName(); 26 | currentThread.setName(name); 27 | } 28 | 29 | @Override 30 | public void onShutdown() 31 | { 32 | Thread.currentThread().setName(oldName); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/dsl/EventProcessorFactory.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.dsl; 2 | 3 | import com.lmax.disruptor.EventProcessor; 4 | import com.lmax.disruptor.RingBuffer; 5 | import com.lmax.disruptor.Sequence; 6 | 7 | /** 8 | * 事件处理器工厂 9 | * A factory interface to make it possible to include custom event processors in a chain: 10 | * 11 | *

12 |  * disruptor.handleEventsWith(handler1).then((ringBuffer, barrierSequences) -> new CustomEventProcessor(ringBuffer, barrierSequences));
13 |  * 
14 | */ 15 | public interface EventProcessorFactory 16 | { 17 | /** 18 | * Create a new event processor that gates on barrierSequences. 19 | * 20 | * @param ringBuffer the ring buffer to receive events from. 21 | * @param barrierSequences the sequences to gate on 22 | * @return a new EventProcessor that gates on barrierSequences before processing events 23 | */ 24 | EventProcessor createEventProcessor(RingBuffer ringBuffer, Sequence[] barrierSequences); 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/SleepingWaitStrategyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import static com.lmax.disruptor.support.WaitStrategyTestUtil.assertWaitForWithDelayOf; 19 | 20 | import org.junit.Test; 21 | 22 | public class SleepingWaitStrategyTest 23 | { 24 | @Test 25 | public void shouldWaitForValue() throws Exception 26 | { 27 | assertWaitForWithDelayOf(50, new SleepingWaitStrategy()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/BusySpinWaitStrategyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import static com.lmax.disruptor.support.WaitStrategyTestUtil.assertWaitForWithDelayOf; 19 | 20 | import org.junit.Test; 21 | 22 | public class BusySpinWaitStrategyTest 23 | { 24 | 25 | @Test 26 | public void shouldWaitForValue() throws Exception 27 | { 28 | assertWaitForWithDelayOf(50, new BusySpinWaitStrategy()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/YieldingWaitStrategyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import static com.lmax.disruptor.support.WaitStrategyTestUtil.assertWaitForWithDelayOf; 19 | 20 | import org.junit.Test; 21 | 22 | public class YieldingWaitStrategyTest 23 | { 24 | 25 | @Test 26 | public void shouldWaitForValue() throws Exception 27 | { 28 | assertWaitForWithDelayOf(50, new YieldingWaitStrategy()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerWrapper.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.dsl; 2 | 3 | import com.lmax.disruptor.ExceptionHandler; 4 | import com.lmax.disruptor.FatalExceptionHandler; 5 | 6 | /** 7 | * 异常处理器的包装对象 8 | * @param 9 | */ 10 | public class ExceptionHandlerWrapper implements ExceptionHandler 11 | { 12 | private ExceptionHandler delegate = new FatalExceptionHandler(); 13 | 14 | public void switchTo(final ExceptionHandler exceptionHandler) 15 | { 16 | this.delegate = exceptionHandler; 17 | } 18 | 19 | @Override 20 | public void handleEventException(final Throwable ex, final long sequence, final T event) 21 | { 22 | delegate.handleEventException(ex, sequence, event); 23 | } 24 | 25 | @Override 26 | public void handleOnStartException(final Throwable ex) 27 | { 28 | delegate.handleOnStartException(ex); 29 | } 30 | 31 | @Override 32 | public void handleOnShutdownException(final Throwable ex) 33 | { 34 | delegate.handleOnShutdownException(ex); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/dsl/stubs/TestWorkHandler.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.dsl.stubs; 2 | 3 | import com.lmax.disruptor.WorkHandler; 4 | import com.lmax.disruptor.support.TestEvent; 5 | 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | 8 | public class TestWorkHandler implements WorkHandler 9 | { 10 | private final AtomicBoolean readyToProcessEvent = new AtomicBoolean(false); 11 | private volatile boolean stopped = false; 12 | 13 | @Override 14 | public void onEvent(final TestEvent event) throws Exception 15 | { 16 | waitForAndSetFlag(false); 17 | } 18 | 19 | public void processEvent() 20 | { 21 | waitForAndSetFlag(true); 22 | } 23 | 24 | public void stopWaiting() 25 | { 26 | stopped = true; 27 | } 28 | 29 | private void waitForAndSetFlag(final boolean newValue) 30 | { 31 | while (!stopped && !Thread.currentThread().isInterrupted() && 32 | !readyToProcessEvent.compareAndSet(!newValue, newValue)) 33 | { 34 | Thread.yield(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/dsl/stubs/SleepingEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.dsl.stubs; 17 | 18 | import com.lmax.disruptor.EventHandler; 19 | import com.lmax.disruptor.support.TestEvent; 20 | 21 | public class SleepingEventHandler implements EventHandler 22 | { 23 | @Override 24 | public void onEvent(final TestEvent entry, final long sequence, final boolean endOfBatch) throws Exception 25 | { 26 | Thread.sleep(1000); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/example/KeyedBatching.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.example; 2 | 3 | import com.lmax.disruptor.EventHandler; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class KeyedBatching implements EventHandler 9 | { 10 | private static final int MAX_BATCH_SIZE = 100; 11 | private long key = 0; 12 | private List batch = new ArrayList(); 13 | 14 | @Override 15 | public void onEvent(KeyedEvent event, long sequence, boolean endOfBatch) throws Exception 16 | { 17 | if (!batch.isEmpty() && event.key != key) 18 | { 19 | processBatch(batch); 20 | } 21 | 22 | batch.add(event.data); 23 | key = event.key; 24 | 25 | if (endOfBatch || batch.size() >= MAX_BATCH_SIZE) 26 | { 27 | processBatch(batch); 28 | } 29 | } 30 | 31 | private void processBatch(List batch) 32 | { 33 | // do work. 34 | batch.clear(); 35 | } 36 | 37 | public static class KeyedEvent 38 | { 39 | long key; 40 | Object data; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/support/TestEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.EventFactory; 19 | 20 | public final class TestEvent 21 | { 22 | @Override 23 | public String toString() 24 | { 25 | return "Test Event"; 26 | } 27 | 28 | public static final EventFactory EVENT_FACTORY = new EventFactory() 29 | { 30 | public TestEvent newInstance() 31 | { 32 | return new TestEvent(); 33 | } 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/util/DaemonThreadFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.util; 17 | 18 | import java.util.concurrent.ThreadFactory; 19 | 20 | /** 21 | * Access to a ThreadFactory instance. All threads are created with setDaemon(true). 22 | */ 23 | public enum DaemonThreadFactory implements ThreadFactory 24 | { 25 | INSTANCE; 26 | 27 | @Override 28 | public Thread newThread(final Runnable r) 29 | { 30 | Thread t = new Thread(r); 31 | t.setDaemon(true); 32 | return t; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/ValueAdditionWorkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.WorkHandler; 19 | 20 | public class ValueAdditionWorkHandler implements WorkHandler 21 | { 22 | private long total; 23 | 24 | @Override 25 | public void onEvent(ValueEvent event) throws Exception 26 | { 27 | long value = event.getValue(); 28 | total += value; 29 | } 30 | 31 | public long getTotal() 32 | { 33 | return total; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/IgnoreExceptionHandlerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import com.lmax.disruptor.support.TestEvent; 19 | import org.junit.Test; 20 | 21 | public final class IgnoreExceptionHandlerTest 22 | { 23 | @Test 24 | public void shouldHandleAndIgnoreException() 25 | { 26 | final Exception ex = new Exception(); 27 | final TestEvent event = new TestEvent(); 28 | 29 | ExceptionHandler exceptionHandler = new IgnoreExceptionHandler(); 30 | exceptionHandler.handleEventException(ex, 0L, event); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/dsl/ProducerType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.dsl; 17 | 18 | /** 19 | * Defines producer types to support creation of RingBuffer with correct sequencer and publisher. 20 | */ 21 | public enum ProducerType 22 | { 23 | /** 24 | * Create a RingBuffer with a single event publisher to the RingBuffer 25 | */ 26 | SINGLE, 27 | 28 | /** 29 | * Create a RingBuffer supporting multiple event publishers to the one RingBuffer 30 | * 单生产者和多生产的主要差别在空间分配上(序号分配上)。 31 | * 在Disruptor下,其实都是多消费者模式,并没有针对单消费者的优化。 32 | */ 33 | MULTI 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/support/LongEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.EventFactory; 19 | 20 | public class LongEvent 21 | { 22 | private long value; 23 | 24 | public void set(long value) 25 | { 26 | this.value = value; 27 | } 28 | 29 | public long get() 30 | { 31 | return value; 32 | } 33 | 34 | public static final EventFactory FACTORY = new EventFactory() 35 | { 36 | @Override 37 | public LongEvent newInstance() 38 | { 39 | return new LongEvent(); 40 | } 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/Cursored.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 该接口是面向消费者的,消费者用于感知生产者的进度。 20 | * 21 | * Implementors of this interface must provide a single long value 22 | * that represents their current cursor value. Used during dynamic 23 | * add/remove of Sequences from a 24 | * {@link SequenceGroups#addSequences(Object, java.util.concurrent.atomic.AtomicReferenceFieldUpdater, Cursored, Sequence...)}. 25 | */ 26 | public interface Cursored 27 | { 28 | /** 29 | * 获取当前的游标值 30 | * Get the current cursor value. 31 | * 32 | * @return current cursor value 33 | */ 34 | long getCursor(); 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/TimeoutBlockingWaitStrategyTest.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | import com.lmax.disruptor.support.DummySequenceBarrier; 4 | import org.junit.Test; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import static org.junit.Assert.assertTrue; 9 | import static org.junit.Assert.fail; 10 | 11 | public class TimeoutBlockingWaitStrategyTest 12 | { 13 | @Test 14 | public void shouldTimeoutWaitFor() throws Exception 15 | { 16 | final SequenceBarrier sequenceBarrier = new DummySequenceBarrier(); 17 | 18 | long theTimeout = 500; 19 | TimeoutBlockingWaitStrategy waitStrategy = new TimeoutBlockingWaitStrategy(theTimeout, TimeUnit.MILLISECONDS); 20 | Sequence cursor = new Sequence(5); 21 | Sequence dependent = cursor; 22 | 23 | long t0 = System.currentTimeMillis(); 24 | 25 | try 26 | { 27 | waitStrategy.waitFor(6, cursor, dependent, sequenceBarrier); 28 | fail("TimeoutException should have been thrown"); 29 | } 30 | catch (TimeoutException e) 31 | { 32 | } 33 | 34 | long t1 = System.currentTimeMillis(); 35 | 36 | long timeWaiting = t1 - t0; 37 | 38 | assertTrue(timeWaiting >= theTimeout); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/ValueEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.EventFactory; 19 | 20 | public final class ValueEvent 21 | { 22 | private long value; 23 | 24 | public long getValue() 25 | { 26 | return value; 27 | } 28 | 29 | public void setValue(final long value) 30 | { 31 | this.value = value; 32 | } 33 | 34 | public static final EventFactory EVENT_FACTORY = new EventFactory() 35 | { 36 | public ValueEvent newInstance() 37 | { 38 | return new ValueEvent(); 39 | } 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/LiteTimeoutBlockingWaitStrategyTest.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | import com.lmax.disruptor.support.DummySequenceBarrier; 4 | import org.junit.Test; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import static org.junit.Assert.assertTrue; 9 | import static org.junit.Assert.fail; 10 | 11 | public class LiteTimeoutBlockingWaitStrategyTest 12 | { 13 | @Test 14 | public void shouldTimeoutWaitFor() throws Exception 15 | { 16 | final SequenceBarrier sequenceBarrier = new DummySequenceBarrier(); 17 | 18 | long theTimeout = 500; 19 | LiteTimeoutBlockingWaitStrategy waitStrategy = new LiteTimeoutBlockingWaitStrategy(theTimeout, TimeUnit.MILLISECONDS); 20 | Sequence cursor = new Sequence(5); 21 | Sequence dependent = cursor; 22 | 23 | long t0 = System.currentTimeMillis(); 24 | 25 | try 26 | { 27 | waitStrategy.waitFor(6, cursor, dependent, sequenceBarrier); 28 | fail("TimeoutException should have been thrown"); 29 | } 30 | catch (TimeoutException e) 31 | { 32 | } 33 | 34 | long t1 = System.currentTimeMillis(); 35 | 36 | long timeWaiting = t1 - t0; 37 | 38 | assertTrue(timeWaiting >= theTimeout); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * RingBuffer使用{@link #newInstance()}预创建对象预填充共享数据区。 20 | * 创建的实际是数据的载体对象,载体对象是反复使用的,会预分配,因此存在短时间的内存泄漏风险, 21 | * 因此讲道理最好每次处理完之后将数据进行清理,以帮助垃圾回收。 22 | * 23 | * Called by the {@link RingBuffer} to pre-populate all the events to fill the RingBuffer. 24 | * @param event implementation storing the data for sharing during exchange or parallel coordination of an event. 25 | */ 26 | public interface EventFactory 27 | { 28 | /* 29 | * Implementations should instantiate an event object, with all memory already allocated where possible. 30 | */ 31 | T newInstance(); 32 | } -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/dsl/stubs/EventHandlerStub.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.dsl.stubs; 17 | 18 | import com.lmax.disruptor.EventHandler; 19 | 20 | import java.util.concurrent.CountDownLatch; 21 | 22 | public class EventHandlerStub implements EventHandler 23 | { 24 | private final CountDownLatch countDownLatch; 25 | 26 | public EventHandlerStub(final CountDownLatch countDownLatch) 27 | { 28 | this.countDownLatch = countDownLatch; 29 | } 30 | 31 | @Override 32 | public void onEvent(final T entry, final long sequence, final boolean endOfBatch) throws Exception 33 | { 34 | countDownLatch.countDown(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/dsl/stubs/EvilEqualsEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.dsl.stubs; 17 | 18 | import com.lmax.disruptor.EventHandler; 19 | import com.lmax.disruptor.support.TestEvent; 20 | 21 | public class EvilEqualsEventHandler implements EventHandler 22 | { 23 | @Override 24 | public void onEvent(final TestEvent entry, final long sequence, boolean endOfBatch) throws Exception 25 | { 26 | } 27 | 28 | @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"}) 29 | public boolean equals(Object o) 30 | { 31 | return true; 32 | } 33 | 34 | public int hashCode() 35 | { 36 | return 1; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/dsl/stubs/ExceptionThrowingEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.dsl.stubs; 17 | 18 | import com.lmax.disruptor.EventHandler; 19 | import com.lmax.disruptor.support.TestEvent; 20 | 21 | public class ExceptionThrowingEventHandler implements EventHandler 22 | { 23 | private final RuntimeException testException; 24 | 25 | public ExceptionThrowingEventHandler(final RuntimeException testException) 26 | { 27 | this.testException = testException; 28 | } 29 | 30 | @Override 31 | public void onEvent(final TestEvent entry, final long sequence, final boolean endOfBatch) throws Exception 32 | { 33 | throw testException; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/EventCountingWorkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.WorkHandler; 19 | import com.lmax.disruptor.util.PaddedLong; 20 | 21 | public final class EventCountingWorkHandler 22 | implements WorkHandler 23 | { 24 | private final PaddedLong[] counters; 25 | private final int index; 26 | 27 | public EventCountingWorkHandler(final PaddedLong[] counters, final int index) 28 | { 29 | this.counters = counters; 30 | this.index = index; 31 | } 32 | 33 | @Override 34 | public void onEvent(final ValueEvent event) throws Exception 35 | { 36 | counters[index].set(counters[index].get() + 1L); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/PerfTestUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | public final class PerfTestUtil 19 | { 20 | public static long accumulatedAddition(final long iterations) 21 | { 22 | long temp = 0L; 23 | for (long i = 0L; i < iterations; i++) 24 | { 25 | temp += i; 26 | } 27 | 28 | return temp; 29 | } 30 | 31 | public static void failIf(long a, long b) 32 | { 33 | if (a == b) 34 | { 35 | throw new RuntimeException(); 36 | } 37 | } 38 | 39 | public static void failIfNot(long a, long b) 40 | { 41 | if (a != b) 42 | { 43 | throw new RuntimeException(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/support/DummyEventProcessor.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.support; 2 | 3 | import com.lmax.disruptor.EventProcessor; 4 | import com.lmax.disruptor.Sequence; 5 | import com.lmax.disruptor.SingleProducerSequencer; 6 | 7 | import java.util.concurrent.atomic.AtomicBoolean; 8 | 9 | public class DummyEventProcessor implements EventProcessor 10 | { 11 | private final Sequence sequence; 12 | private final AtomicBoolean running = new AtomicBoolean(false); 13 | 14 | public DummyEventProcessor(Sequence sequence) 15 | { 16 | this.sequence = sequence; 17 | } 18 | 19 | public DummyEventProcessor() 20 | { 21 | this(new Sequence(SingleProducerSequencer.INITIAL_CURSOR_VALUE)); 22 | } 23 | 24 | public void setSequence(long sequence) 25 | { 26 | this.sequence.set(sequence); 27 | } 28 | 29 | @Override 30 | public Sequence getSequence() 31 | { 32 | return sequence; 33 | } 34 | 35 | @Override 36 | public void halt() 37 | { 38 | running.set(false); 39 | } 40 | 41 | @Override 42 | public boolean isRunning() 43 | { 44 | return running.get(); 45 | } 46 | 47 | @Override 48 | public void run() 49 | { 50 | if (!running.compareAndSet(false, true)) 51 | { 52 | throw new IllegalStateException("Already running"); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventTranslatorVararg.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * Implementations translate another data representations into events claimed from the {@link RingBuffer} 20 | * 21 | * @param event implementation storing the data for sharing during exchange or parallel coordination of an event. 22 | * @see EventTranslator 23 | */ 24 | public interface EventTranslatorVararg 25 | { 26 | /** 27 | * Translate a data representation into fields set in given event 28 | * 29 | * @param event into which the data should be translated. 30 | * @param sequence that is assigned to event. 31 | * @param args The array of user arguments. 32 | */ 33 | void translateTo(T event, long sequence, Object... args); 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/FixedSequenceGroupTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import static org.hamcrest.CoreMatchers.is; 19 | import static org.junit.Assert.assertThat; 20 | 21 | import org.junit.Test; 22 | 23 | 24 | public class FixedSequenceGroupTest 25 | { 26 | 27 | @Test 28 | public void shouldReturnMinimumOf2Sequences() throws Exception 29 | { 30 | Sequence sequence1 = new Sequence(34); 31 | Sequence sequnece2 = new Sequence(47); 32 | Sequence group = new FixedSequenceGroup(new Sequence[]{sequence1, sequnece2}); 33 | 34 | assertThat(group.get(), is(34L)); 35 | sequence1.set(35); 36 | assertThat(group.get(), is(35L)); 37 | sequence1.set(48); 38 | assertThat(group.get(), is(47L)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/util/PaddedLong.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.util; 17 | 18 | /** 19 | * Cache line padded long variable to be used when false sharing maybe an issue. 20 | */ 21 | public final class PaddedLong extends MutableLong 22 | { 23 | public volatile long p1, p2, p3, p4, p5, p6 = 7L; 24 | 25 | /** 26 | * Default constructor 27 | */ 28 | public PaddedLong() 29 | { 30 | } 31 | 32 | /** 33 | * Construct with an initial value. 34 | * 35 | * @param initialValue for construction 36 | */ 37 | public PaddedLong(final long initialValue) 38 | { 39 | super(initialValue); 40 | } 41 | 42 | public long sumPaddingToPreventOptimisation() 43 | { 44 | return p1 + p2 + p3 + p4 + p5 + p6; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/LifecycleAware.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 事件处理器生命周期通知 20 | * 21 | * 如果你的EventHandler实现了该接口,则事件处理器在启动和停止的时候都会收到通知.(可能多次启动-停止) 22 | * 23 | * Implement this interface in your {@link EventHandler} to be notified when a thread for the 24 | * {@link BatchEventProcessor} starts and shuts down. 25 | */ 26 | public interface LifecycleAware 27 | { 28 | /** 29 | * Called once on thread start before first event is available. 30 | */ 31 | void onStart(); 32 | 33 | /** 34 | *

Called once just before the thread is shutdown.

35 | *

36 | * Sequence event processing will already have stopped before this method is called. No events will 37 | * be processed after this message. 38 | */ 39 | void onShutdown(); 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/FatalExceptionHandlerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import com.lmax.disruptor.support.TestEvent; 19 | import org.junit.Assert; 20 | import org.junit.Test; 21 | 22 | public final class FatalExceptionHandlerTest 23 | { 24 | @Test 25 | public void shouldHandleFatalException() 26 | { 27 | final Exception causeException = new Exception(); 28 | final TestEvent event = new TestEvent(); 29 | 30 | ExceptionHandler exceptionHandler = new FatalExceptionHandler(); 31 | 32 | try 33 | { 34 | exceptionHandler.handleEventException(causeException, 0L, event); 35 | } 36 | catch (RuntimeException ex) 37 | { 38 | Assert.assertEquals(causeException, ex.getCause()); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/Operation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | public enum Operation 19 | { 20 | ADDITION 21 | { 22 | @Override 23 | public long op(final long lhs, final long rhs) 24 | { 25 | return lhs + rhs; 26 | } 27 | }, 28 | 29 | SUBTRACTION 30 | { 31 | @Override 32 | public long op(final long lhs, final long rhs) 33 | { 34 | return lhs - rhs; 35 | } 36 | }, 37 | 38 | AND 39 | { 40 | @Override 41 | public long op(final long lhs, final long rhs) 42 | { 43 | return lhs & rhs; 44 | } 45 | }; 46 | 47 | public abstract long op(long lhs, long rhs); 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventTranslatorOneArg.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 带参数的数据传输对象 20 | * Transfer Object 21 | * Implementations translate another data representations into events claimed from the {@link RingBuffer} 22 | * 23 | * @param event implementation storing the data for sharing during exchange or parallel coordination of an event. 24 | * @see EventTranslator 25 | */ 26 | public interface EventTranslatorOneArg 27 | { 28 | /** 29 | * Translate a data representation into fields set in given event 30 | * 31 | * @param event into which the data should be translated. 32 | * @param sequence that is assigned to event. 33 | * @param arg0 The first user specified argument to the translator 34 | */ 35 | void translateTo(T event, long sequence, A arg0); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventTranslatorTwoArg.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * Implementations translate another data representations into events claimed from the {@link RingBuffer} 20 | * 21 | * @param event implementation storing the data for sharing during exchange or parallel coordination of an event. 22 | * @see EventTranslator 23 | */ 24 | public interface EventTranslatorTwoArg 25 | { 26 | /** 27 | * Translate a data representation into fields set in given event 28 | * 29 | * @param event into which the data should be translated. 30 | * @param sequence that is assigned to event. 31 | * @param arg0 The first user specified argument to the translator 32 | * @param arg1 The second user specified argument to the translator 33 | */ 34 | void translateTo(T event, long sequence, A arg0, B arg1); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/WorkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 它是{@link WorkProcessor}处理事件的实现,两者之间是组合关系,{@link WorkProcessor}负责跟踪和拉取事件,{@link WorkHandler}负责处理事件。 20 | * 手动加粗:{@link WorkHandler}不是消费者。 21 | * 22 | * Callback interface to be implemented for processing units of work as they become available in the {@link RingBuffer}. 23 | * 24 | * @param event implementation storing the data for sharing during exchange or parallel coordination of an event. 25 | * @see WorkerPool 26 | */ 27 | public interface WorkHandler 28 | { 29 | /** 30 | * Callback to indicate a unit of work needs to be processed. 31 | * 32 | * @param event published to the {@link RingBuffer} 33 | * @throws Exception if the {@link WorkHandler} would like the exception handled further up the chain. 34 | */ 35 | void onEvent(T event) throws Exception; 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/support/DummySequenceBarrier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | 19 | import com.lmax.disruptor.AlertException; 20 | import com.lmax.disruptor.SequenceBarrier; 21 | 22 | public class DummySequenceBarrier implements SequenceBarrier 23 | { 24 | @Override 25 | public long waitFor(long sequence) throws AlertException, InterruptedException 26 | { 27 | return 0; 28 | } 29 | 30 | @Override 31 | public long getCursor() 32 | { 33 | return 0; 34 | } 35 | 36 | @Override 37 | public boolean isAlerted() 38 | { 39 | return false; 40 | } 41 | 42 | @Override 43 | public void alert() 44 | { 45 | } 46 | 47 | @Override 48 | public void clearAlert() 49 | { 50 | } 51 | 52 | @Override 53 | public void checkAlert() throws AlertException 54 | { 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/InsufficientCapacityException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 空间不足异常,在申请共享数据结构的空间时可能抛出。 20 | * 用异常代理其它返回值,受检异常,在编码时就需要显示处理。 21 | * 22 | * 为了性能考虑,该异常没有堆栈信息,并且是单例的。 23 | *

Exception thrown when it is not possible to insert a value into 24 | * the ring buffer without it wrapping the consuming sequences. Used 25 | * specifically when claiming with the {@link RingBuffer#tryNext()} call.

26 | * 27 | *

For efficiency this exception will not have a stack trace.

28 | */ 29 | @SuppressWarnings("serial") 30 | public final class InsufficientCapacityException extends Exception 31 | { 32 | public static final InsufficientCapacityException INSTANCE = new InsufficientCapacityException(); 33 | 34 | private InsufficientCapacityException() 35 | { 36 | // Singleton 37 | } 38 | 39 | @Override 40 | public synchronized Throwable fillInStackTrace() 41 | { 42 | return this; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventTranslatorThreeArg.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * Implementations translate another data representations into events claimed from the {@link RingBuffer} 20 | * 21 | * @param event implementation storing the data for sharing during exchange or parallel coordination of an event. 22 | * @see EventTranslator 23 | */ 24 | public interface EventTranslatorThreeArg 25 | { 26 | /** 27 | * Translate a data representation into fields set in given event 28 | * 29 | * @param event into which the data should be translated. 30 | * @param sequence that is assigned to event. 31 | * @param arg0 The first user specified argument to the translator 32 | * @param arg1 The second user specified argument to the translator 33 | * @param arg2 The third user specified argument to the translator 34 | */ 35 | void translateTo(T event, long sequence, A arg0, B arg1, C arg2); 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/dsl/stubs/StubExceptionHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.dsl.stubs; 17 | 18 | import com.lmax.disruptor.ExceptionHandler; 19 | 20 | import java.util.concurrent.atomic.AtomicReference; 21 | 22 | public class StubExceptionHandler implements ExceptionHandler 23 | { 24 | private final AtomicReference exceptionHandled; 25 | 26 | public StubExceptionHandler(final AtomicReference exceptionHandled) 27 | { 28 | this.exceptionHandled = exceptionHandled; 29 | } 30 | 31 | public void handleEventException(final Throwable ex, final long sequence, final Object event) 32 | { 33 | exceptionHandled.set(ex); 34 | } 35 | 36 | @Override 37 | public void handleOnStartException(final Throwable ex) 38 | { 39 | exceptionHandled.set(ex); 40 | } 41 | 42 | @Override 43 | public void handleOnShutdownException(final Throwable ex) 44 | { 45 | exceptionHandled.set(ex); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/MultiProducerSequencerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import static org.hamcrest.CoreMatchers.is; 19 | import static org.junit.Assert.assertThat; 20 | 21 | import org.junit.Test; 22 | 23 | public class MultiProducerSequencerTest 24 | { 25 | private final Sequencer publisher = new MultiProducerSequencer(1024, new BlockingWaitStrategy()); 26 | 27 | @Test 28 | public void shouldOnlyAllowMessagesToBeAvailableIfSpecificallyPublished() throws Exception 29 | { 30 | publisher.publish(3); 31 | publisher.publish(5); 32 | 33 | assertThat(publisher.isAvailable(0), is(false)); 34 | assertThat(publisher.isAvailable(1), is(false)); 35 | assertThat(publisher.isAvailable(2), is(false)); 36 | assertThat(publisher.isAvailable(3), is(true)); 37 | assertThat(publisher.isAvailable(4), is(false)); 38 | assertThat(publisher.isAvailable(5), is(true)); 39 | assertThat(publisher.isAvailable(6), is(false)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventTranslator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 事件传输对象,将数据传输到指定事件对象上 20 | * TO(transfer object) 数据传输对象,基本也是每个事件对应一个对象。 21 | * 22 | *

Implementations translate (write) data representations into events claimed from the {@link RingBuffer}.

23 | * 24 | *

When publishing to the RingBuffer, provide an EventTranslator. The RingBuffer will select the next available 25 | * event by sequence and provide it to the EventTranslator (which should update the event), before publishing 26 | * the sequence update.

27 | * 28 | * @param event implementation storing the data for sharing during exchange or parallel coordination of an event. 29 | */ 30 | public interface EventTranslator 31 | { 32 | /** 33 | * 将数据传输到指定事件对象上。 34 | * Translate a data representation into fields set in given event 35 | * 36 | * @param event into which the data should be translated. 37 | * @param sequence that is assigned to event. 38 | */ 39 | void translateTo(T event, long sequence); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/dsl/ConsumerInfo.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.dsl; 2 | 3 | import com.lmax.disruptor.Sequence; 4 | import com.lmax.disruptor.SequenceBarrier; 5 | 6 | import java.util.concurrent.Executor; 7 | 8 | /** 9 | * 一个消费者信息的抽象, 10 | */ 11 | interface ConsumerInfo 12 | { 13 | /** 14 | * 获取消费者拥有的所有的序列,一个消费者可能有多个Sequence,消费者的消费进度由最小的Sequence决定。 15 | * 这里返回数组类型,其实仅仅是为了避免{@link com.lmax.disruptor.FixedSequenceGroup}。 16 | */ 17 | Sequence[] getSequences(); 18 | 19 | /** 20 | * 获取当前消费者持有的序列屏障。 21 | * 其作用详见{@link SequenceBarrier} 22 | * 23 | * {@link com.lmax.disruptor.Sequencer#newBarrier(Sequence...)} 24 | */ 25 | SequenceBarrier getBarrier(); 26 | 27 | /** 28 | * 当前消费者是否是消费链末端的消费者(没有后继消费者)。 29 | * 如果是末端的消费者,那么它就是生产者关注的消费者(网关序列)。 30 | * 31 | * {@link com.lmax.disruptor.Sequencer#addGatingSequences(Sequence...)} 32 | * {@link com.lmax.disruptor.Sequencer#removeGatingSequence(Sequence)}} 33 | * {@link com.lmax.disruptor.AbstractSequencer#gatingSequences} 34 | */ 35 | boolean isEndOfChain(); 36 | 37 | /** 38 | * 启动消费者。 39 | * 主要是为每一个{@link com.lmax.disruptor.EventProcessor}创建线程,启动事件监听。 40 | */ 41 | void start(Executor executor); 42 | 43 | /** 44 | * 通知消费者处理完当前事件之后,停止下来 45 | * 类似线程中断或任务的取消操作 46 | * {@link java.util.concurrent.Future#cancel(boolean)} 47 | * {@link Thread#interrupt()} 48 | */ 49 | void halt(); 50 | 51 | /** 52 | * 当我新增了后继消费者的时候,标记为不是消费者链末端的消费者 53 | * 生产者就不再需要对我保持关注 54 | */ 55 | void markAsUsedInBarrier(); 56 | 57 | /** 58 | * 消费者当前是否正在运行 59 | */ 60 | boolean isRunning(); 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/dsl/WorkerPoolInfo.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.dsl; 2 | 3 | import com.lmax.disruptor.*; 4 | 5 | import java.util.concurrent.Executor; 6 | 7 | /** 8 | * 线程池消费者信息对象/工作者池信息。 9 | * (WorkPool整体是一个消费者,是一个多线程的消费者) 10 | * @param 11 | */ 12 | class WorkerPoolInfo implements ConsumerInfo 13 | { 14 | /** 15 | * 工作者池 16 | */ 17 | private final WorkerPool workerPool; 18 | /** 19 | * 消费者对应的序列屏障,屏障用于协调与生产者或其他消费者之间的速度和保证可见性 20 | */ 21 | private final SequenceBarrier sequenceBarrier; 22 | /** 23 | * 是否是消费链的末端消费者(没有后继消费者) 24 | */ 25 | private boolean endOfChain = true; 26 | 27 | WorkerPoolInfo(final WorkerPool workerPool, final SequenceBarrier sequenceBarrier) 28 | { 29 | this.workerPool = workerPool; 30 | this.sequenceBarrier = sequenceBarrier; 31 | } 32 | 33 | @Override 34 | public Sequence[] getSequences() 35 | { 36 | return workerPool.getWorkerSequences(); 37 | } 38 | 39 | @Override 40 | public SequenceBarrier getBarrier() 41 | { 42 | return sequenceBarrier; 43 | } 44 | 45 | @Override 46 | public boolean isEndOfChain() 47 | { 48 | return endOfChain; 49 | } 50 | 51 | @Override 52 | public void start(Executor executor) 53 | { 54 | workerPool.start(executor); 55 | } 56 | 57 | @Override 58 | public void halt() 59 | { 60 | workerPool.halt(); 61 | } 62 | 63 | @Override 64 | public void markAsUsedInBarrier() 65 | { 66 | endOfChain = false; 67 | } 68 | 69 | @Override 70 | public boolean isRunning() 71 | { 72 | return workerPool.isRunning(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/dsl/stubs/StubPublisher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.dsl.stubs; 17 | 18 | import com.lmax.disruptor.RingBuffer; 19 | import com.lmax.disruptor.support.TestEvent; 20 | 21 | public class StubPublisher implements Runnable 22 | { 23 | private volatile boolean running = true; 24 | private volatile int publicationCount = 0; 25 | 26 | private final RingBuffer ringBuffer; 27 | 28 | public StubPublisher(final RingBuffer ringBuffer) 29 | { 30 | this.ringBuffer = ringBuffer; 31 | } 32 | 33 | public void run() 34 | { 35 | while (running) 36 | { 37 | final long sequence = ringBuffer.next(); 38 | //final TestEvent entry = ringBuffer.get(sequence); 39 | ringBuffer.publish(sequence); 40 | publicationCount++; 41 | } 42 | } 43 | 44 | public int getPublicationCount() 45 | { 46 | return publicationCount; 47 | } 48 | 49 | public void halt() 50 | { 51 | running = false; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/ValueAdditionEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import java.util.concurrent.CountDownLatch; 19 | 20 | import com.lmax.disruptor.EventHandler; 21 | import com.lmax.disruptor.util.PaddedLong; 22 | 23 | public final class ValueAdditionEventHandler implements EventHandler 24 | { 25 | private final PaddedLong value = new PaddedLong(); 26 | private long count; 27 | private CountDownLatch latch; 28 | 29 | public long getValue() 30 | { 31 | return value.get(); 32 | } 33 | 34 | public void reset(final CountDownLatch latch, final long expectedCount) 35 | { 36 | value.set(0L); 37 | this.latch = latch; 38 | count = expectedCount; 39 | } 40 | 41 | @Override 42 | public void onEvent(final ValueEvent event, final long sequence, final boolean endOfBatch) throws Exception 43 | { 44 | value.set(value.get() + event.getValue()); 45 | 46 | if (count == sequence) 47 | { 48 | latch.countDown(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/immutable/CustomPerformanceTest.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.immutable; 2 | 3 | import java.util.concurrent.locks.LockSupport; 4 | 5 | import com.lmax.disruptor.BatchEventProcessor; 6 | import com.lmax.disruptor.SingleProducerSequencer; 7 | import com.lmax.disruptor.YieldingWaitStrategy; 8 | 9 | public class CustomPerformanceTest 10 | { 11 | private final CustomRingBuffer ringBuffer; 12 | 13 | public CustomPerformanceTest() 14 | { 15 | ringBuffer = 16 | new CustomRingBuffer(new SingleProducerSequencer(Constants.SIZE, new YieldingWaitStrategy())); 17 | } 18 | 19 | public void run() 20 | { 21 | try 22 | { 23 | doRun(); 24 | } 25 | catch (InterruptedException e) 26 | { 27 | e.printStackTrace(); 28 | } 29 | } 30 | 31 | private void doRun() throws InterruptedException 32 | { 33 | BatchEventProcessor batchEventProcessor = ringBuffer.createHandler(new SimpleEventHandler()); 34 | 35 | Thread t = new Thread(batchEventProcessor); 36 | t.start(); 37 | 38 | long iterations = Constants.ITERATIONS; 39 | for (long l = 0; l < iterations; l++) 40 | { 41 | SimpleEvent e = new SimpleEvent(l, l, l, l); 42 | ringBuffer.put(e); 43 | } 44 | 45 | while (batchEventProcessor.getSequence().get() != iterations - 1) 46 | { 47 | LockSupport.parkNanos(1); 48 | } 49 | 50 | batchEventProcessor.halt(); 51 | t.join(); 52 | } 53 | 54 | public static void main(String[] args) 55 | { 56 | new CustomPerformanceTest().run(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/util/MutableLong.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.util; 17 | 18 | /** 19 | * Holder class for a long value. 20 | */ 21 | public class MutableLong 22 | { 23 | private long value = 0L; 24 | 25 | /** 26 | * Default constructor 27 | */ 28 | public MutableLong() 29 | { 30 | } 31 | 32 | /** 33 | * Construct the holder with initial value. 34 | * 35 | * @param initialValue to be initially set. 36 | */ 37 | public MutableLong(final long initialValue) 38 | { 39 | this.value = initialValue; 40 | } 41 | 42 | /** 43 | * Get the long value. 44 | * 45 | * @return the long value. 46 | */ 47 | public long get() 48 | { 49 | return value; 50 | } 51 | 52 | /** 53 | * Set the long value. 54 | * 55 | * @param value to set. 56 | */ 57 | public void set(final long value) 58 | { 59 | this.value = value; 60 | } 61 | 62 | /** 63 | * Increments the value 64 | */ 65 | public void increment() 66 | { 67 | value++; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/EventCountingAndReleasingWorkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.EventReleaseAware; 19 | import com.lmax.disruptor.EventReleaser; 20 | import com.lmax.disruptor.WorkHandler; 21 | import com.lmax.disruptor.util.PaddedLong; 22 | 23 | public final class EventCountingAndReleasingWorkHandler 24 | implements WorkHandler, EventReleaseAware 25 | { 26 | private final PaddedLong[] counters; 27 | private final int index; 28 | private EventReleaser eventReleaser; 29 | 30 | public EventCountingAndReleasingWorkHandler(final PaddedLong[] counters, final int index) 31 | { 32 | this.counters = counters; 33 | this.index = index; 34 | } 35 | 36 | @Override 37 | public void onEvent(final ValueEvent event) throws Exception 38 | { 39 | eventReleaser.release(); 40 | counters[index].set(counters[index].get() + 1L); 41 | } 42 | 43 | @Override 44 | public void setEventReleaser(final EventReleaser eventReleaser) 45 | { 46 | this.eventReleaser = eventReleaser; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/LongArrayEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import java.util.concurrent.CountDownLatch; 19 | 20 | import com.lmax.disruptor.EventHandler; 21 | import com.lmax.disruptor.util.PaddedLong; 22 | 23 | public final class LongArrayEventHandler implements EventHandler 24 | { 25 | private final PaddedLong value = new PaddedLong(); 26 | private long count; 27 | private CountDownLatch latch; 28 | 29 | public long getValue() 30 | { 31 | return value.get(); 32 | } 33 | 34 | public void reset(final CountDownLatch latch, final long expectedCount) 35 | { 36 | value.set(0L); 37 | this.latch = latch; 38 | count = expectedCount; 39 | } 40 | 41 | @Override 42 | public void onEvent(final long[] event, final long sequence, final boolean endOfBatch) throws Exception 43 | { 44 | for (int i = 0; i < event.length; i++) 45 | { 46 | value.set(value.get() + event[i]); 47 | } 48 | 49 | if (--count == 0) 50 | { 51 | latch.countDown(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/ValueQueuePublisher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import java.util.concurrent.BlockingQueue; 19 | import java.util.concurrent.CyclicBarrier; 20 | 21 | public final class ValueQueuePublisher implements Runnable 22 | { 23 | private final CyclicBarrier cyclicBarrier; 24 | private final BlockingQueue blockingQueue; 25 | private final long iterations; 26 | 27 | public ValueQueuePublisher( 28 | final CyclicBarrier cyclicBarrier, final BlockingQueue blockingQueue, final long iterations) 29 | { 30 | this.cyclicBarrier = cyclicBarrier; 31 | this.blockingQueue = blockingQueue; 32 | this.iterations = iterations; 33 | } 34 | 35 | @Override 36 | public void run() 37 | { 38 | try 39 | { 40 | cyclicBarrier.await(); 41 | for (long i = 0; i < iterations; i++) 42 | { 43 | blockingQueue.put(Long.valueOf(i)); 44 | } 45 | } 46 | catch (Exception ex) 47 | { 48 | throw new RuntimeException(ex); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/util/UtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.util; 17 | 18 | import com.lmax.disruptor.Sequence; 19 | 20 | import org.junit.Assert; 21 | import org.junit.Test; 22 | 23 | public final class UtilTest 24 | { 25 | @Test 26 | public void shouldReturnNextPowerOfTwo() 27 | { 28 | int powerOfTwo = Util.ceilingNextPowerOfTwo(1000); 29 | 30 | Assert.assertEquals(1024, powerOfTwo); 31 | } 32 | 33 | @Test 34 | public void shouldReturnExactPowerOfTwo() 35 | { 36 | int powerOfTwo = Util.ceilingNextPowerOfTwo(1024); 37 | 38 | Assert.assertEquals(1024, powerOfTwo); 39 | } 40 | 41 | @Test 42 | public void shouldReturnMinimumSequence() 43 | { 44 | final Sequence[] sequences = {new Sequence(7L), new Sequence(3L), new Sequence(12L)}; 45 | Assert.assertEquals(3L, Util.getMinimumSequence(sequences)); 46 | } 47 | 48 | @Test 49 | public void shouldReturnLongMaxWhenNoEventProcessors() 50 | { 51 | final Sequence[] sequences = new Sequence[0]; 52 | 53 | Assert.assertEquals(Long.MAX_VALUE, Util.getMinimumSequence(sequences)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/AlertException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 一个用于唤醒的异常。使用了异常机制,但是是为了发出通知的。 20 | * 21 | * 用于通知在SequenceBarrier上等待的EventProcessor,有状态发生了改变 22 | * 其实很像 {@link InterruptedException},很像中断异常 23 | * 24 | * 由于性能原因,该异常不会获取堆栈信息。 25 | * 26 | * Used to alert {@link EventProcessor}s waiting at a {@link SequenceBarrier} of status changes. 27 | *

28 | * It does not fill in a stack trace for performance reasons. 29 | */ 30 | @SuppressWarnings("serial") 31 | public final class AlertException extends Exception 32 | { 33 | /** 34 | * Pre-allocated exception to avoid garbage generation 35 | */ 36 | public static final AlertException INSTANCE = new AlertException(); 37 | 38 | /** 39 | * Private constructor so only a single instance exists. 40 | */ 41 | private AlertException() 42 | { 43 | } 44 | 45 | /** 46 | * Overridden so the stack trace is not filled in for this exception for performance reasons. 47 | * 48 | * @return this instance. 49 | */ 50 | @Override 51 | public Throwable fillInStackTrace() 52 | { 53 | return this; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/FizzBuzzEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.EventFactory; 19 | 20 | public final class FizzBuzzEvent 21 | { 22 | private boolean fizz = false; 23 | private boolean buzz = false; 24 | private long value = 0; 25 | 26 | public long getValue() 27 | { 28 | return value; 29 | } 30 | 31 | public void setValue(final long value) 32 | { 33 | fizz = false; 34 | buzz = false; 35 | this.value = value; 36 | } 37 | 38 | public boolean isFizz() 39 | { 40 | return fizz; 41 | } 42 | 43 | public void setFizz(final boolean fizz) 44 | { 45 | this.fizz = fizz; 46 | } 47 | 48 | public boolean isBuzz() 49 | { 50 | return buzz; 51 | } 52 | 53 | public void setBuzz(final boolean buzz) 54 | { 55 | this.buzz = buzz; 56 | } 57 | 58 | public static final EventFactory EVENT_FACTORY = new EventFactory() 59 | { 60 | public FizzBuzzEvent newInstance() 61 | { 62 | return new FizzBuzzEvent(); 63 | } 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/EventTranslatorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import com.lmax.disruptor.support.StubEvent; 19 | import org.junit.Assert; 20 | import org.junit.Test; 21 | 22 | public final class EventTranslatorTest 23 | { 24 | private static final String TEST_VALUE = "Wibble"; 25 | 26 | @Test 27 | public void shouldTranslateOtherDataIntoAnEvent() 28 | { 29 | StubEvent event = StubEvent.EVENT_FACTORY.newInstance(); 30 | EventTranslator eventTranslator = new ExampleEventTranslator(TEST_VALUE); 31 | 32 | eventTranslator.translateTo(event, 0); 33 | 34 | Assert.assertEquals(TEST_VALUE, event.getTestString()); 35 | } 36 | 37 | public static final class ExampleEventTranslator 38 | implements EventTranslator 39 | { 40 | private final String testValue; 41 | 42 | public ExampleEventTranslator(final String testValue) 43 | { 44 | this.testValue = testValue; 45 | } 46 | 47 | @Override 48 | public void translateTo(final StubEvent event, long sequence) 49 | { 50 | event.setTestString(testValue); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/EventCountingQueueProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.util.PaddedLong; 19 | 20 | import java.util.concurrent.BlockingQueue; 21 | 22 | public final class EventCountingQueueProcessor implements Runnable 23 | { 24 | private volatile boolean running; 25 | private final BlockingQueue blockingQueue; 26 | private final PaddedLong[] counters; 27 | private final int index; 28 | 29 | public EventCountingQueueProcessor( 30 | final BlockingQueue blockingQueue, final PaddedLong[] counters, final int index) 31 | { 32 | this.blockingQueue = blockingQueue; 33 | this.counters = counters; 34 | this.index = index; 35 | } 36 | 37 | public void halt() 38 | { 39 | running = false; 40 | } 41 | 42 | @Override 43 | public void run() 44 | { 45 | running = true; 46 | while (running) 47 | { 48 | try 49 | { 50 | blockingQueue.take(); 51 | counters[index].set(counters[index].get() + 1L); 52 | } 53 | catch (InterruptedException ex) 54 | { 55 | break; 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/ValueMutationEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.EventHandler; 19 | import com.lmax.disruptor.util.PaddedLong; 20 | 21 | import java.util.concurrent.CountDownLatch; 22 | 23 | public final class ValueMutationEventHandler implements EventHandler 24 | { 25 | private final Operation operation; 26 | private final PaddedLong value = new PaddedLong(); 27 | private long count; 28 | private CountDownLatch latch; 29 | 30 | public ValueMutationEventHandler(final Operation operation) 31 | { 32 | this.operation = operation; 33 | } 34 | 35 | public long getValue() 36 | { 37 | return value.get(); 38 | } 39 | 40 | public void reset(final CountDownLatch latch, final long expectedCount) 41 | { 42 | value.set(0L); 43 | this.latch = latch; 44 | count = expectedCount; 45 | } 46 | 47 | @Override 48 | public void onEvent(final ValueEvent event, final long sequence, final boolean endOfBatch) throws Exception 49 | { 50 | value.set(operation.op(value.get(), event.getValue())); 51 | 52 | if (count == sequence) 53 | { 54 | latch.countDown(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/ValuePublisher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import java.util.concurrent.CyclicBarrier; 19 | 20 | import com.lmax.disruptor.RingBuffer; 21 | 22 | public final class ValuePublisher implements Runnable 23 | { 24 | private final CyclicBarrier cyclicBarrier; 25 | private final RingBuffer ringBuffer; 26 | private final long iterations; 27 | 28 | public ValuePublisher( 29 | final CyclicBarrier cyclicBarrier, final RingBuffer ringBuffer, final long iterations) 30 | { 31 | this.cyclicBarrier = cyclicBarrier; 32 | this.ringBuffer = ringBuffer; 33 | this.iterations = iterations; 34 | } 35 | 36 | @Override 37 | public void run() 38 | { 39 | try 40 | { 41 | cyclicBarrier.await(); 42 | 43 | for (long i = 0; i < iterations; i++) 44 | { 45 | long sequence = ringBuffer.next(); 46 | ValueEvent event = ringBuffer.get(sequence); 47 | event.setValue(i); 48 | ringBuffer.publish(sequence); 49 | } 50 | } 51 | catch (Exception ex) 52 | { 53 | throw new RuntimeException(ex); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/support/WaitStrategyTestUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.AlertException; 19 | import com.lmax.disruptor.Sequence; 20 | import com.lmax.disruptor.TimeoutException; 21 | import com.lmax.disruptor.WaitStrategy; 22 | 23 | import java.util.concurrent.BrokenBarrierException; 24 | import java.util.concurrent.ExecutorService; 25 | import java.util.concurrent.Executors; 26 | 27 | import static org.hamcrest.CoreMatchers.is; 28 | import static org.junit.Assert.assertThat; 29 | 30 | public class WaitStrategyTestUtil 31 | { 32 | private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(); 33 | 34 | public static void assertWaitForWithDelayOf(long sleepTimeMillis, WaitStrategy waitStrategy) 35 | throws InterruptedException, BrokenBarrierException, AlertException, TimeoutException 36 | { 37 | SequenceUpdater sequenceUpdater = new SequenceUpdater(sleepTimeMillis, waitStrategy); 38 | EXECUTOR.execute(sequenceUpdater); 39 | sequenceUpdater.waitForStartup(); 40 | Sequence cursor = new Sequence(0); 41 | long sequence = waitStrategy.waitFor(0, cursor, sequenceUpdater.sequence, new DummySequenceBarrier()); 42 | 43 | assertThat(sequence, is(0L)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/example/SequentialThreeConsumers.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.example; 2 | 3 | import com.lmax.disruptor.EventFactory; 4 | import com.lmax.disruptor.EventHandler; 5 | import com.lmax.disruptor.dsl.Disruptor; 6 | import com.lmax.disruptor.util.DaemonThreadFactory; 7 | 8 | public class SequentialThreeConsumers 9 | { 10 | private static class MyEvent 11 | { 12 | private Object a; 13 | private Object b; 14 | private Object c; 15 | private Object d; 16 | } 17 | 18 | private static EventFactory factory = new EventFactory() 19 | { 20 | @Override 21 | public MyEvent newInstance() 22 | { 23 | return new MyEvent(); 24 | } 25 | }; 26 | 27 | private static EventHandler handler1 = new EventHandler() 28 | { 29 | @Override 30 | public void onEvent(MyEvent event, long sequence, boolean endOfBatch) throws Exception 31 | { 32 | event.b = event.a; 33 | } 34 | }; 35 | 36 | private static EventHandler handler2 = new EventHandler() 37 | { 38 | @Override 39 | public void onEvent(MyEvent event, long sequence, boolean endOfBatch) throws Exception 40 | { 41 | event.c = event.b; 42 | } 43 | }; 44 | 45 | private static EventHandler handler3 = new EventHandler() 46 | { 47 | @Override 48 | public void onEvent(MyEvent event, long sequence, boolean endOfBatch) throws Exception 49 | { 50 | event.d = event.c; 51 | } 52 | }; 53 | 54 | public static void main(String[] args) 55 | { 56 | Disruptor disruptor = new Disruptor(factory, 1024, DaemonThreadFactory.INSTANCE); 57 | 58 | disruptor.handleEventsWith(handler1).then(handler2).then(handler3); 59 | 60 | disruptor.start(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/support/SequenceUpdater.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.Sequence; 19 | import com.lmax.disruptor.WaitStrategy; 20 | 21 | import java.util.concurrent.BrokenBarrierException; 22 | import java.util.concurrent.CyclicBarrier; 23 | 24 | class SequenceUpdater implements Runnable 25 | { 26 | public final Sequence sequence = new Sequence(); 27 | private final CyclicBarrier barrier = new CyclicBarrier(2); 28 | private final long sleepTime; 29 | private WaitStrategy waitStrategy; 30 | 31 | SequenceUpdater(long sleepTime, WaitStrategy waitStrategy) 32 | { 33 | this.sleepTime = sleepTime; 34 | this.waitStrategy = waitStrategy; 35 | } 36 | 37 | @Override 38 | public void run() 39 | { 40 | try 41 | { 42 | barrier.await(); 43 | if (0 != sleepTime) 44 | { 45 | Thread.sleep(sleepTime); 46 | } 47 | sequence.incrementAndGet(); 48 | waitStrategy.signalAllWhenBlocking(); 49 | } 50 | catch (Exception e) 51 | { 52 | e.printStackTrace(); 53 | } 54 | } 55 | 56 | public void waitForStartup() throws InterruptedException, BrokenBarrierException 57 | { 58 | barrier.await(); 59 | } 60 | } -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/RingBufferEventMatcher.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | import org.hamcrest.Description; 4 | import org.hamcrest.Factory; 5 | import org.hamcrest.Matcher; 6 | import org.hamcrest.TypeSafeMatcher; 7 | 8 | import static org.hamcrest.CoreMatchers.is; 9 | 10 | final class RingBufferEventMatcher extends TypeSafeMatcher> 11 | { 12 | private final Matcher[] expectedValueMatchers; 13 | 14 | private RingBufferEventMatcher(final Matcher[] expectedValueMatchers) 15 | { 16 | this.expectedValueMatchers = expectedValueMatchers; 17 | } 18 | 19 | @Factory 20 | public static RingBufferEventMatcher ringBufferWithEvents(final Matcher... valueMatchers) 21 | { 22 | return new RingBufferEventMatcher(valueMatchers); 23 | } 24 | 25 | @Factory 26 | public static RingBufferEventMatcher ringBufferWithEvents(final Object... values) 27 | { 28 | Matcher[] valueMatchers = new Matcher[values.length]; 29 | for (int i = 0; i < values.length; i++) 30 | { 31 | final Object value = values[i]; 32 | valueMatchers[i] = is(value); 33 | } 34 | return new RingBufferEventMatcher(valueMatchers); 35 | } 36 | 37 | @Override 38 | public boolean matchesSafely(final RingBuffer ringBuffer) 39 | { 40 | boolean matches = true; 41 | for (int i = 0; i < expectedValueMatchers.length; i++) 42 | { 43 | final Matcher expectedValueMatcher = expectedValueMatchers[i]; 44 | matches &= expectedValueMatcher.matches(ringBuffer.get(i)[0]); 45 | } 46 | return matches; 47 | } 48 | 49 | @Override 50 | public void describeTo(final Description description) 51 | { 52 | description.appendText("Expected ring buffer with events matching: "); 53 | 54 | for (Matcher expectedValueMatcher : expectedValueMatchers) 55 | { 56 | expectedValueMatcher.describeTo(description); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/IgnoreExceptionHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | /** 22 | * 执行忽略的异常异常处理器,仅仅打个日志 23 | * 24 | * Convenience implementation of an exception handler that using standard JDK logging to log 25 | * the exception as {@link Level}.INFO 26 | */ 27 | public final class IgnoreExceptionHandler implements ExceptionHandler 28 | { 29 | private static final Logger LOGGER = Logger.getLogger(IgnoreExceptionHandler.class.getName()); 30 | private final Logger logger; 31 | 32 | public IgnoreExceptionHandler() 33 | { 34 | this.logger = LOGGER; 35 | } 36 | 37 | public IgnoreExceptionHandler(final Logger logger) 38 | { 39 | this.logger = logger; 40 | } 41 | 42 | @Override 43 | public void handleEventException(final Throwable ex, final long sequence, final Object event) 44 | { 45 | logger.log(Level.INFO, "Exception processing: " + sequence + " " + event, ex); 46 | } 47 | 48 | @Override 49 | public void handleOnStartException(final Throwable ex) 50 | { 51 | logger.log(Level.INFO, "Exception during onStart()", ex); 52 | } 53 | 54 | @Override 55 | public void handleOnShutdownException(final Throwable ex) 56 | { 57 | logger.log(Level.INFO, "Exception during onShutdown()", ex); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/example/WaitForShutdown.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.example; 2 | 3 | import com.lmax.disruptor.EventHandler; 4 | import com.lmax.disruptor.LifecycleAware; 5 | import com.lmax.disruptor.TimeoutException; 6 | import com.lmax.disruptor.dsl.Disruptor; 7 | import com.lmax.disruptor.support.LongEvent; 8 | import com.lmax.disruptor.util.DaemonThreadFactory; 9 | 10 | import java.util.concurrent.CountDownLatch; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | public class WaitForShutdown 14 | { 15 | private static volatile int value = 0; 16 | 17 | private static class Handler implements EventHandler, LifecycleAware 18 | { 19 | private final CountDownLatch latch; 20 | 21 | Handler(CountDownLatch latch) 22 | { 23 | this.latch = latch; 24 | } 25 | 26 | @Override 27 | public void onStart() 28 | { 29 | } 30 | 31 | @Override 32 | public void onShutdown() 33 | { 34 | latch.countDown(); 35 | } 36 | 37 | @Override 38 | public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception 39 | { 40 | value = 1; 41 | } 42 | } 43 | 44 | public static void main(String[] args) throws TimeoutException, InterruptedException 45 | { 46 | Disruptor disruptor = new Disruptor( 47 | LongEvent.FACTORY, 16, DaemonThreadFactory.INSTANCE 48 | ); 49 | 50 | CountDownLatch shutdownLatch = new CountDownLatch(2); 51 | 52 | disruptor.handleEventsWith(new Handler(shutdownLatch)).then(new Handler(shutdownLatch)); 53 | disruptor.start(); 54 | 55 | long next = disruptor.getRingBuffer().next(); 56 | disruptor.getRingBuffer().get(next).set(next); 57 | disruptor.getRingBuffer().publish(next); 58 | 59 | disruptor.shutdown(10, TimeUnit.SECONDS); 60 | 61 | shutdownLatch.await(); 62 | 63 | System.out.println(value); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/BusySpinWaitStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | 19 | import com.lmax.disruptor.util.ThreadHints; 20 | 21 | /** 22 | * 该策略使用自旋(空循环)来在barrier上等待。 23 | * 该策略通过占用CPU资源去比避免系统调用带来的延迟抖动。最好在线程能绑定到特定的CPU核心时使用。 24 | * (会持续占用CPU资源,基本不会让出CPU资源) 25 | *

26 | * 特征:极低的延迟,极高的吞吐量,以及极高的CPU占用。 27 | *

28 | * 如果你要使用该等待策略,确保有足够的CPU资源,且你能接受它带来的CPU使用率。 29 | * 30 | * Busy Spin strategy that uses a busy spin loop for {@link com.lmax.disruptor.EventProcessor}s waiting on a barrier. 31 | *

32 | * This strategy will use CPU resource to avoid syscalls which can introduce latency jitter. It is best 33 | * used when threads can be bound to specific CPU cores. 34 | */ 35 | public final class BusySpinWaitStrategy implements WaitStrategy 36 | { 37 | @Override 38 | public long waitFor( 39 | final long sequence, Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier) 40 | throws AlertException, InterruptedException 41 | { 42 | long availableSequence; 43 | 44 | // 确保该序号已经被我前面的消费者消费(协调与其他消费者的关系) 45 | while ((availableSequence = dependentSequence.get()) < sequence) 46 | { 47 | barrier.checkAlert(); 48 | // 自旋等待 49 | ThreadHints.onSpinWait(); 50 | } 51 | 52 | return availableSequence; 53 | } 54 | 55 | @Override 56 | public void signalAllWhenBlocking() 57 | { 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/FunctionEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.EventFactory; 19 | 20 | public final class FunctionEvent 21 | { 22 | private long operandOne; 23 | private long operandTwo; 24 | private long stepOneResult; 25 | private long stepTwoResult; 26 | 27 | public long getOperandOne() 28 | { 29 | return operandOne; 30 | } 31 | 32 | public void setOperandOne(final long operandOne) 33 | { 34 | this.operandOne = operandOne; 35 | } 36 | 37 | public long getOperandTwo() 38 | { 39 | return operandTwo; 40 | } 41 | 42 | public void setOperandTwo(final long operandTwo) 43 | { 44 | this.operandTwo = operandTwo; 45 | } 46 | 47 | public long getStepOneResult() 48 | { 49 | return stepOneResult; 50 | } 51 | 52 | public void setStepOneResult(final long stepOneResult) 53 | { 54 | this.stepOneResult = stepOneResult; 55 | } 56 | 57 | public long getStepTwoResult() 58 | { 59 | return stepTwoResult; 60 | } 61 | 62 | public void setStepTwoResult(final long stepTwoResult) 63 | { 64 | this.stepTwoResult = stepTwoResult; 65 | } 66 | 67 | public static final EventFactory EVENT_FACTORY = new EventFactory() 68 | { 69 | public FunctionEvent newInstance() 70 | { 71 | return new FunctionEvent(); 72 | } 73 | }; 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/example/HandleExceptionOnTranslate.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.example; 2 | 3 | import com.lmax.disruptor.EventHandler; 4 | import com.lmax.disruptor.EventTranslator; 5 | import com.lmax.disruptor.dsl.Disruptor; 6 | import com.lmax.disruptor.support.LongEvent; 7 | import com.lmax.disruptor.util.DaemonThreadFactory; 8 | 9 | public class HandleExceptionOnTranslate 10 | { 11 | private static final int NO_VALUE_SPECIFIED = -1; 12 | 13 | private static class MyHandler implements EventHandler 14 | { 15 | 16 | @Override 17 | public void onEvent(LongEvent event, long sequence, boolean endOfBatch) throws Exception 18 | { 19 | if (event.get() == NO_VALUE_SPECIFIED) 20 | { 21 | System.out.printf("Discarded%n"); 22 | } 23 | else 24 | { 25 | System.out.printf("Processed: %s%n", event.get() == sequence); 26 | } 27 | } 28 | } 29 | 30 | public static void main(String[] args) throws InterruptedException 31 | { 32 | Disruptor disruptor = new Disruptor(LongEvent.FACTORY, 1024, DaemonThreadFactory.INSTANCE); 33 | 34 | disruptor.handleEventsWith(new MyHandler()); 35 | 36 | disruptor.start(); 37 | 38 | EventTranslator t = new EventTranslator() 39 | { 40 | @Override 41 | public void translateTo(LongEvent event, long sequence) 42 | { 43 | event.set(NO_VALUE_SPECIFIED); 44 | 45 | if (sequence % 3 == 0) 46 | { 47 | throw new RuntimeException("Skipping"); 48 | } 49 | 50 | event.set(sequence); 51 | } 52 | }; 53 | 54 | for (int i = 0; i < 10; i++) 55 | { 56 | try 57 | { 58 | disruptor.publishEvent(t); 59 | } 60 | catch (RuntimeException e) 61 | { 62 | // Skipping 63 | } 64 | } 65 | 66 | Thread.sleep(5000); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/SequenceReportingEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * Sequence提交,用于获取BatchEventProcessor绑定的Sequence?现在还没有对应的代码推断到底干嘛的(可能还在开发)。 20 | * 用于BatchEventProcessor设置一个回调,允许EventHandler在完成事件消费之后进行通知。 21 | * 22 | * 23 | * 通常,这将在handler执行某些批处理操作(例如写入IO设备)时使用; 24 | * 在操作完成后,接口的实现者应该调用{@link Sequence#set}来更新序列,并允许依赖于此处理程序的其他进程进行。 25 | * 26 | * Used by the {@link BatchEventProcessor} to set a callback allowing the {@link EventHandler} to notify 27 | * when it has finished consuming an event if this happens after the {@link EventHandler#onEvent(Object, long, boolean)} call. 28 | *

29 | * Typically this would be used when the handler is performing some sort of batching operation such as writing to an IO 30 | * device; after the operation has completed, the implementation should call {@link Sequence#set} to update the 31 | * sequence and allow other processes that are dependent on this handler to progress. 32 | * 33 | * @param event implementation storing the data for sharing during exchange or parallel coordination of an event. 34 | */ 35 | public interface SequenceReportingEventHandler 36 | extends EventHandler 37 | { 38 | /** 39 | * 用于BatchEventProcessor建立回调机制。 40 | * Call by the {@link BatchEventProcessor} to setup the callback. 41 | * 42 | * @param sequenceCallback callback on which to notify the {@link BatchEventProcessor} that the sequence has progressed. 43 | */ 44 | void setSequenceCallback(Sequence sequenceCallback); 45 | } 46 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/LongArrayPublisher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import java.util.concurrent.CyclicBarrier; 19 | 20 | import com.lmax.disruptor.RingBuffer; 21 | 22 | public final class LongArrayPublisher implements Runnable 23 | { 24 | private final CyclicBarrier cyclicBarrier; 25 | private final RingBuffer ringBuffer; 26 | private final long iterations; 27 | private final long arraySize; 28 | 29 | public LongArrayPublisher( 30 | final CyclicBarrier cyclicBarrier, 31 | final RingBuffer ringBuffer, 32 | final long iterations, 33 | final long arraySize) 34 | { 35 | this.cyclicBarrier = cyclicBarrier; 36 | this.ringBuffer = ringBuffer; 37 | this.iterations = iterations; 38 | this.arraySize = arraySize; 39 | } 40 | 41 | @Override 42 | public void run() 43 | { 44 | try 45 | { 46 | cyclicBarrier.await(); 47 | 48 | for (long i = 0; i < iterations; i++) 49 | { 50 | long sequence = ringBuffer.next(); 51 | long[] event = ringBuffer.get(sequence); 52 | for (int j = 0; j < arraySize; j++) 53 | { 54 | event[j] = i + j; 55 | } 56 | ringBuffer.publish(sequence); 57 | } 58 | } 59 | catch (Exception ex) 60 | { 61 | throw new RuntimeException(ex); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/primitive/LongRingBuffer.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.primitive; 2 | 3 | import com.lmax.disruptor.BatchEventProcessor; 4 | import com.lmax.disruptor.DataProvider; 5 | import com.lmax.disruptor.EventHandler; 6 | import com.lmax.disruptor.Sequencer; 7 | 8 | public class LongRingBuffer 9 | { 10 | private final Sequencer sequencer; 11 | private final long[] buffer; 12 | private final int mask; 13 | 14 | public LongRingBuffer(final Sequencer sequencer) 15 | { 16 | this.sequencer = sequencer; 17 | this.buffer = new long[sequencer.getBufferSize()]; 18 | this.mask = sequencer.getBufferSize() - 1; 19 | } 20 | 21 | private int index(final long sequence) 22 | { 23 | return (int) sequence & mask; 24 | } 25 | 26 | public void put(final long e) 27 | { 28 | final long next = sequencer.next(); 29 | buffer[index(next)] = e; 30 | sequencer.publish(next); 31 | } 32 | 33 | public interface LongHandler 34 | { 35 | void onEvent(long value, long sequence, boolean endOfBatch); 36 | } 37 | 38 | private class LongEvent implements DataProvider 39 | { 40 | private long sequence; 41 | 42 | public long get() 43 | { 44 | return buffer[index(sequence)]; 45 | } 46 | 47 | @Override 48 | public LongEvent get(final long sequence) 49 | { 50 | this.sequence = sequence; 51 | return this; 52 | } 53 | } 54 | 55 | public BatchEventProcessor createProcessor(final LongHandler handler) 56 | { 57 | return new BatchEventProcessor( 58 | new LongEvent(), 59 | sequencer.newBarrier(), 60 | new EventHandler() 61 | { 62 | @Override 63 | public void onEvent(final LongEvent event, final long sequence, final boolean endOfBatch) 64 | throws Exception 65 | { 66 | handler.onEvent(event.get(), sequence, endOfBatch); 67 | } 68 | }); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/ExceptionHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 异常处理器,在处理事件发生异常时,将会回调到这里的方法。 20 | * 最好为Disruptor设置一个你确定的异常处理器的,默认的处理器会导致EventProcessor退出执行。 21 | * {@link com.lmax.disruptor.dsl.Disruptor#handleExceptionsFor(EventHandler)} 22 | * 23 | * Callback handler for uncaught exceptions in the event processing cycle of the {@link BatchEventProcessor} 24 | */ 25 | public interface ExceptionHandler 26 | { 27 | /** 28 | *

Strategy for handling uncaught exceptions when processing an event.

29 | * 30 | *

If the strategy wishes to terminate further processing by the {@link BatchEventProcessor} 31 | * then it should throw a {@link RuntimeException}.

32 | * 33 | * @param ex the exception that propagated from the {@link EventHandler}. 34 | * @param sequence of the event which cause the exception. 35 | * @param event being processed when the exception occurred. This can be null. 36 | */ 37 | void handleEventException(Throwable ex, long sequence, T event); 38 | 39 | /** 40 | * Callback to notify of an exception during {@link LifecycleAware#onStart()} 41 | * 42 | * @param ex throw during the starting process. 43 | */ 44 | void handleOnStartException(Throwable ex); 45 | 46 | /** 47 | * Callback to notify of an exception during {@link LifecycleAware#onShutdown()} 48 | * 49 | * @param ex throw during the shutdown process. 50 | */ 51 | void handleOnShutdownException(Throwable ex); 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/FatalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | /** 22 | * 严重错误异常处理器,是默认的异常处理器,会导致EventProcessor退出!!! 23 | * 会将捕获到的异常包装为RuntimeException抛出,从而导致EventProcessor退出执行。 24 | * 25 | * Convenience implementation of an exception handler that using standard JDK logging to log 26 | * the exception as {@link Level}.SEVERE and re-throw it wrapped in a {@link RuntimeException} 27 | */ 28 | public final class FatalExceptionHandler implements ExceptionHandler 29 | { 30 | private static final Logger LOGGER = Logger.getLogger(FatalExceptionHandler.class.getName()); 31 | private final Logger logger; 32 | 33 | public FatalExceptionHandler() 34 | { 35 | this.logger = LOGGER; 36 | } 37 | 38 | public FatalExceptionHandler(final Logger logger) 39 | { 40 | this.logger = logger; 41 | } 42 | 43 | @Override 44 | public void handleEventException(final Throwable ex, final long sequence, final Object event) 45 | { 46 | logger.log(Level.SEVERE, "Exception processing: " + sequence + " " + event, ex); 47 | 48 | throw new RuntimeException(ex); 49 | } 50 | 51 | @Override 52 | public void handleOnStartException(final Throwable ex) 53 | { 54 | logger.log(Level.SEVERE, "Exception during onStart()", ex); 55 | } 56 | 57 | @Override 58 | public void handleOnShutdownException(final Throwable ex) 59 | { 60 | logger.log(Level.SEVERE, "Exception during onShutdown()", ex); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/ValueBatchPublisher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import java.util.concurrent.CyclicBarrier; 19 | 20 | import com.lmax.disruptor.RingBuffer; 21 | 22 | public final class ValueBatchPublisher implements Runnable 23 | { 24 | private final CyclicBarrier cyclicBarrier; 25 | private final RingBuffer ringBuffer; 26 | private final long iterations; 27 | private final int batchSize; 28 | 29 | public ValueBatchPublisher( 30 | final CyclicBarrier cyclicBarrier, 31 | final RingBuffer ringBuffer, 32 | final long iterations, 33 | final int batchSize) 34 | { 35 | this.cyclicBarrier = cyclicBarrier; 36 | this.ringBuffer = ringBuffer; 37 | this.iterations = iterations; 38 | this.batchSize = batchSize; 39 | } 40 | 41 | @Override 42 | public void run() 43 | { 44 | try 45 | { 46 | cyclicBarrier.await(); 47 | 48 | for (long i = 0; i < iterations; i += batchSize) 49 | { 50 | long hi = ringBuffer.next(batchSize); 51 | long lo = hi - (batchSize - 1); 52 | for (long l = lo; l <= hi; l++) 53 | { 54 | ValueEvent event = ringBuffer.get(l); 55 | event.setValue(l); 56 | } 57 | ringBuffer.publish(lo, hi); 58 | } 59 | } 60 | catch (Exception ex) 61 | { 62 | throw new RuntimeException(ex); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/PhasedBackoffWaitStrategyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import static com.lmax.disruptor.support.WaitStrategyTestUtil.assertWaitForWithDelayOf; 19 | import static java.util.concurrent.TimeUnit.MILLISECONDS; 20 | 21 | import org.junit.Test; 22 | 23 | public class PhasedBackoffWaitStrategyTest 24 | { 25 | @Test 26 | public void shouldHandleImmediateSequenceChange() throws Exception 27 | { 28 | assertWaitForWithDelayOf(0, PhasedBackoffWaitStrategy.withLock(1, 1, MILLISECONDS)); 29 | assertWaitForWithDelayOf(0, PhasedBackoffWaitStrategy.withSleep(1, 1, MILLISECONDS)); 30 | } 31 | 32 | @Test 33 | public void shouldHandleSequenceChangeWithOneMillisecondDelay() throws Exception 34 | { 35 | assertWaitForWithDelayOf(1, PhasedBackoffWaitStrategy.withLock(1, 1, MILLISECONDS)); 36 | assertWaitForWithDelayOf(1, PhasedBackoffWaitStrategy.withSleep(1, 1, MILLISECONDS)); 37 | } 38 | 39 | @Test 40 | public void shouldHandleSequenceChangeWithTwoMillisecondDelay() throws Exception 41 | { 42 | assertWaitForWithDelayOf(2, PhasedBackoffWaitStrategy.withLock(1, 1, MILLISECONDS)); 43 | assertWaitForWithDelayOf(2, PhasedBackoffWaitStrategy.withSleep(1, 1, MILLISECONDS)); 44 | } 45 | 46 | @Test 47 | public void shouldHandleSequenceChangeWithTenMillisecondDelay() throws Exception 48 | { 49 | assertWaitForWithDelayOf(10, PhasedBackoffWaitStrategy.withLock(1, 1, MILLISECONDS)); 50 | assertWaitForWithDelayOf(10, PhasedBackoffWaitStrategy.withSleep(1, 1, MILLISECONDS)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/support/TestWaiter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.concurrent.Callable; 21 | import java.util.concurrent.CyclicBarrier; 22 | 23 | import com.lmax.disruptor.RingBuffer; 24 | import com.lmax.disruptor.SequenceBarrier; 25 | 26 | public final class TestWaiter implements Callable> 27 | { 28 | private final long toWaitForSequence; 29 | private final long initialSequence; 30 | private final CyclicBarrier cyclicBarrier; 31 | private final SequenceBarrier sequenceBarrier; 32 | private final RingBuffer ringBuffer; 33 | 34 | public TestWaiter( 35 | final CyclicBarrier cyclicBarrier, 36 | final SequenceBarrier sequenceBarrier, 37 | final RingBuffer ringBuffer, 38 | final long initialSequence, 39 | final long toWaitForSequence) 40 | { 41 | this.cyclicBarrier = cyclicBarrier; 42 | this.initialSequence = initialSequence; 43 | this.ringBuffer = ringBuffer; 44 | this.toWaitForSequence = toWaitForSequence; 45 | this.sequenceBarrier = sequenceBarrier; 46 | } 47 | 48 | @Override 49 | public List call() throws Exception 50 | { 51 | cyclicBarrier.await(); 52 | sequenceBarrier.waitFor(toWaitForSequence); 53 | 54 | final List messages = new ArrayList(); 55 | for (long l = initialSequence; l <= toWaitForSequence; l++) 56 | { 57 | messages.add(ringBuffer.get(l)); 58 | } 59 | 60 | return messages; 61 | } 62 | } -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/AbstractPerfTestDisruptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | 19 | public abstract class AbstractPerfTestDisruptor 20 | { 21 | public static final int RUNS = 7; 22 | 23 | protected void testImplementations() 24 | throws Exception 25 | { 26 | final int availableProcessors = Runtime.getRuntime().availableProcessors(); 27 | if (getRequiredProcessorCount() > availableProcessors) 28 | { 29 | System.out.print("*** Warning ***: your system has insufficient processors to execute the test efficiently. "); 30 | System.out.println("Processors required = " + getRequiredProcessorCount() + " available = " + availableProcessors); 31 | } 32 | 33 | long[] disruptorOps = new long[RUNS]; 34 | 35 | System.out.println("Starting Disruptor tests"); 36 | for (int i = 0; i < RUNS; i++) 37 | { 38 | System.gc(); 39 | disruptorOps[i] = runDisruptorPass(); 40 | System.out.format("Run %d, Disruptor=%,d ops/sec%n", i, Long.valueOf(disruptorOps[i])); 41 | } 42 | } 43 | 44 | public static void printResults(final String className, final long[] disruptorOps, final long[] queueOps) 45 | { 46 | for (int i = 0; i < RUNS; i++) 47 | { 48 | System.out.format("%s run %d: BlockingQueue=%,d Disruptor=%,d ops/sec\n", 49 | className, Integer.valueOf(i), Long.valueOf(queueOps[i]), Long.valueOf(disruptorOps[i])); 50 | } 51 | } 52 | 53 | protected abstract int getRequiredProcessorCount(); 54 | 55 | protected abstract long runDisruptorPass() throws Exception; 56 | } 57 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/AbstractPerfTestQueue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | 19 | public abstract class AbstractPerfTestQueue 20 | { 21 | public static final int RUNS = 7; 22 | 23 | protected void testImplementations() 24 | throws Exception 25 | { 26 | final int availableProcessors = Runtime.getRuntime().availableProcessors(); 27 | if (getRequiredProcessorCount() > availableProcessors) 28 | { 29 | System.out.print( 30 | "*** Warning ***: your system has insufficient processors to execute the test efficiently. "); 31 | System.out.println( 32 | "Processors required = " + getRequiredProcessorCount() + " available = " + availableProcessors); 33 | } 34 | 35 | long[] queueOps = new long[RUNS]; 36 | 37 | System.out.println("Starting Queue tests"); 38 | for (int i = 0; i < RUNS; i++) 39 | { 40 | System.gc(); 41 | queueOps[i] = runQueuePass(); 42 | System.out.format("Run %d, BlockingQueue=%,d ops/sec%n", i, Long.valueOf(queueOps[i])); 43 | } 44 | } 45 | 46 | public static void printResults(final String className, final long[] disruptorOps, final long[] queueOps) 47 | { 48 | for (int i = 0; i < RUNS; i++) 49 | { 50 | System.out.format( 51 | "%s run %d: BlockingQueue=%,d Disruptor=%,d ops/sec\n", 52 | className, Integer.valueOf(i), Long.valueOf(queueOps[i]), Long.valueOf(disruptorOps[i])); 53 | } 54 | } 55 | 56 | protected abstract int getRequiredProcessorCount(); 57 | 58 | protected abstract long runQueuePass() throws Exception; 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/example/PullWithPoller.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.example; 2 | 3 | import com.lmax.disruptor.EventFactory; 4 | import com.lmax.disruptor.EventPoller; 5 | import com.lmax.disruptor.RingBuffer; 6 | 7 | /** 8 | * Created by barkerm on 02/02/15. 9 | */ 10 | public class PullWithPoller 11 | { 12 | public static class DataEvent 13 | { 14 | T data; 15 | 16 | public static EventFactory> factory() 17 | { 18 | return new EventFactory>() 19 | { 20 | @Override 21 | public DataEvent newInstance() 22 | { 23 | return new DataEvent(); 24 | } 25 | }; 26 | } 27 | 28 | public T copyOfData() 29 | { 30 | // Copy the data out here. In this case we have a single reference object, so the pass by 31 | // reference is sufficient. But if we were reusing a byte array, then we would need to copy 32 | // the actual contents. 33 | return data; 34 | } 35 | } 36 | 37 | public static void main(String[] args) throws Exception 38 | { 39 | RingBuffer> ringBuffer = RingBuffer.createMultiProducer(DataEvent.factory(), 1024); 40 | 41 | final EventPoller> poller = ringBuffer.newPoller(); 42 | 43 | Object value = getNextValue(poller); 44 | 45 | // Value could be null if no events are available. 46 | if (null != value) 47 | { 48 | // Process value. 49 | } 50 | } 51 | 52 | private static Object getNextValue(EventPoller> poller) throws Exception 53 | { 54 | final Object[] out = new Object[1]; 55 | 56 | poller.poll( 57 | new EventPoller.Handler>() 58 | { 59 | @Override 60 | public boolean onEvent(DataEvent event, long sequence, boolean endOfBatch) throws Exception 61 | { 62 | out[0] = event.copyOfData(); 63 | 64 | // Return false so that only one event is processed at a time. 65 | return false; 66 | } 67 | }); 68 | 69 | return out[0]; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/ValueAdditionQueueProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import java.util.concurrent.BlockingQueue; 19 | import java.util.concurrent.CountDownLatch; 20 | 21 | public final class ValueAdditionQueueProcessor implements Runnable 22 | { 23 | private volatile boolean running; 24 | private long value; 25 | private long sequence; 26 | private CountDownLatch latch; 27 | 28 | private final BlockingQueue blockingQueue; 29 | private final long count; 30 | 31 | public ValueAdditionQueueProcessor(final BlockingQueue blockingQueue, final long count) 32 | { 33 | this.blockingQueue = blockingQueue; 34 | this.count = count; 35 | } 36 | 37 | public long getValue() 38 | { 39 | return value; 40 | } 41 | 42 | public void reset(final CountDownLatch latch) 43 | { 44 | value = 0L; 45 | sequence = 0L; 46 | this.latch = latch; 47 | } 48 | 49 | public void halt() 50 | { 51 | running = false; 52 | } 53 | 54 | @Override 55 | public void run() 56 | { 57 | running = true; 58 | while (true) 59 | { 60 | try 61 | { 62 | long value = blockingQueue.take().longValue(); 63 | this.value += value; 64 | 65 | if (sequence++ == count) 66 | { 67 | latch.countDown(); 68 | } 69 | } 70 | catch (InterruptedException ex) 71 | { 72 | if (!running) 73 | { 74 | break; 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/EventPublisherTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import static com.lmax.disruptor.RingBuffer.createMultiProducer; 19 | import static org.hamcrest.CoreMatchers.is; 20 | import static org.junit.Assert.assertThat; 21 | 22 | import org.junit.Test; 23 | 24 | import com.lmax.disruptor.support.LongEvent; 25 | 26 | public class EventPublisherTest implements EventTranslator 27 | { 28 | private static final int BUFFER_SIZE = 32; 29 | private RingBuffer ringBuffer = createMultiProducer(LongEvent.FACTORY, BUFFER_SIZE); 30 | 31 | @Test 32 | public void shouldPublishEvent() 33 | { 34 | ringBuffer.addGatingSequences(new NoOpEventProcessor(ringBuffer).getSequence()); 35 | 36 | ringBuffer.publishEvent(this); 37 | ringBuffer.publishEvent(this); 38 | 39 | assertThat(Long.valueOf(ringBuffer.get(0).get()), is(Long.valueOf(0 + 29L))); 40 | assertThat(Long.valueOf(ringBuffer.get(1).get()), is(Long.valueOf(1 + 29L))); 41 | } 42 | 43 | @Test 44 | public void shouldTryPublishEvent() throws Exception 45 | { 46 | ringBuffer.addGatingSequences(new Sequence()); 47 | 48 | for (int i = 0; i < BUFFER_SIZE; i++) 49 | { 50 | assertThat(ringBuffer.tryPublishEvent(this), is(true)); 51 | } 52 | 53 | for (int i = 0; i < BUFFER_SIZE; i++) 54 | { 55 | assertThat(Long.valueOf(ringBuffer.get(i).get()), is(Long.valueOf(i + 29L))); 56 | } 57 | 58 | assertThat(ringBuffer.tryPublishEvent(this), is(false)); 59 | } 60 | 61 | @Override 62 | public void translateTo(LongEvent event, long sequence) 63 | { 64 | event.set(sequence + 29); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/immutable/SimplePerformanceTest.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.immutable; 2 | 3 | import java.util.concurrent.locks.LockSupport; 4 | 5 | import com.lmax.disruptor.BatchEventProcessor; 6 | import com.lmax.disruptor.EventTranslatorOneArg; 7 | import com.lmax.disruptor.RingBuffer; 8 | import com.lmax.disruptor.YieldingWaitStrategy; 9 | 10 | public class SimplePerformanceTest 11 | { 12 | private final RingBuffer ringBuffer; 13 | private final EventHolderHandler eventHolderHandler; 14 | 15 | public SimplePerformanceTest() 16 | { 17 | ringBuffer = RingBuffer.createSingleProducer(EventHolder.FACTORY, Constants.SIZE, new YieldingWaitStrategy()); 18 | eventHolderHandler = new EventHolderHandler(new SimpleEventHandler()); 19 | } 20 | 21 | public void run() 22 | { 23 | try 24 | { 25 | doRun(); 26 | } 27 | catch (InterruptedException e) 28 | { 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | private void doRun() throws InterruptedException 34 | { 35 | BatchEventProcessor batchEventProcessor = 36 | new BatchEventProcessor( 37 | ringBuffer, 38 | ringBuffer.newBarrier(), 39 | eventHolderHandler); 40 | ringBuffer.addGatingSequences(batchEventProcessor.getSequence()); 41 | 42 | Thread t = new Thread(batchEventProcessor); 43 | t.start(); 44 | 45 | long iterations = Constants.ITERATIONS; 46 | for (long l = 0; l < iterations; l++) 47 | { 48 | SimpleEvent e = new SimpleEvent(l, l, l, l); 49 | ringBuffer.publishEvent(TRANSLATOR, e); 50 | } 51 | 52 | while (batchEventProcessor.getSequence().get() != iterations - 1) 53 | { 54 | LockSupport.parkNanos(1); 55 | } 56 | 57 | batchEventProcessor.halt(); 58 | t.join(); 59 | } 60 | 61 | private static final EventTranslatorOneArg TRANSLATOR = 62 | new EventTranslatorOneArg() 63 | { 64 | @Override 65 | public void translateTo(EventHolder holder, long arg1, SimpleEvent event) 66 | { 67 | holder.event = event; 68 | } 69 | }; 70 | 71 | public static void main(String[] args) 72 | { 73 | new SimplePerformanceTest().run(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/FunctionEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.EventHandler; 19 | import com.lmax.disruptor.util.PaddedLong; 20 | 21 | import java.util.concurrent.CountDownLatch; 22 | 23 | public final class FunctionEventHandler implements EventHandler 24 | { 25 | private final FunctionStep functionStep; 26 | private final PaddedLong stepThreeCounter = new PaddedLong(); 27 | private long count; 28 | private CountDownLatch latch; 29 | 30 | public FunctionEventHandler(final FunctionStep functionStep) 31 | { 32 | this.functionStep = functionStep; 33 | } 34 | 35 | public long getStepThreeCounter() 36 | { 37 | return stepThreeCounter.get(); 38 | } 39 | 40 | public void reset(final CountDownLatch latch, final long expectedCount) 41 | { 42 | stepThreeCounter.set(0L); 43 | this.latch = latch; 44 | count = expectedCount; 45 | } 46 | 47 | @Override 48 | public void onEvent(final FunctionEvent event, final long sequence, final boolean endOfBatch) throws Exception 49 | { 50 | switch (functionStep) 51 | { 52 | case ONE: 53 | event.setStepOneResult(event.getOperandOne() + event.getOperandTwo()); 54 | break; 55 | 56 | case TWO: 57 | event.setStepTwoResult(event.getStepOneResult() + 3L); 58 | break; 59 | 60 | case THREE: 61 | if ((event.getStepTwoResult() & 4L) == 4L) 62 | { 63 | stepThreeCounter.set(stepThreeCounter.get() + 1L); 64 | } 65 | break; 66 | } 67 | 68 | if (latch != null && count == sequence) 69 | { 70 | latch.countDown(); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/ValueMutationQueueProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import java.util.concurrent.BlockingQueue; 19 | import java.util.concurrent.CountDownLatch; 20 | 21 | public final class ValueMutationQueueProcessor implements Runnable 22 | { 23 | private volatile boolean running; 24 | private long value; 25 | private long sequence; 26 | private CountDownLatch latch; 27 | 28 | private final BlockingQueue blockingQueue; 29 | private final Operation operation; 30 | private final long count; 31 | 32 | public ValueMutationQueueProcessor( 33 | final BlockingQueue blockingQueue, final Operation operation, final long count) 34 | { 35 | this.blockingQueue = blockingQueue; 36 | this.operation = operation; 37 | this.count = count; 38 | } 39 | 40 | public long getValue() 41 | { 42 | return value; 43 | } 44 | 45 | public void reset(final CountDownLatch latch) 46 | { 47 | value = 0L; 48 | sequence = 0L; 49 | this.latch = latch; 50 | } 51 | 52 | public void halt() 53 | { 54 | running = false; 55 | } 56 | 57 | @Override 58 | public void run() 59 | { 60 | running = true; 61 | while (true) 62 | { 63 | try 64 | { 65 | long value = blockingQueue.take().longValue(); 66 | this.value = operation.op(this.value, value); 67 | 68 | if (sequence++ == count) 69 | { 70 | latch.countDown(); 71 | } 72 | } 73 | catch (InterruptedException ex) 74 | { 75 | if (!running) 76 | { 77 | break; 78 | } 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 事件处理器(EventHandler的代理对象) 20 | * 一个事件处理器实现Runnable接口,在轮询时使用适当的等待策略(WaitStrategy)从RingBuffer中轮询获取可用事件(拉取数据)。 21 | * 你最好不实现该接口而是优先使用EventHandler接口和BatchEventProcessor。 22 | * 23 | * 划重点: 24 | * 1.事件处理器是最小的事件处理单元,继承Runnable接口,是一个无限执行的任务(轮询监听),在运行时不会让出线程,因此每一个事件处理器需要独立的线程。 25 | * 2.一个消费者中可能只有一个事件处理器(BatchEventProcessor),也可能有多个事件处理器(WorkPool)。 26 | * 3.BatchEventProcessor既是事件处理器,也是消费者。 27 | * WorkProcessor是事件处理器,但不是消费者,WorkPool才是消费者。 28 | * 4.管理消费者,其实也是管理消费们的所有事件处理器。 29 | * 5.每一个事件处理器都有自己独立的Sequence(进度),如果是多个事件处理器协作的话,这些处理器之间会进行同步。 30 | * 31 | * An EventProcessor needs to be an implementation of a runnable that will poll for events from the {@link RingBuffer} 32 | * using the appropriate wait strategy. It is unlikely that you will need to implement this interface yourself. 33 | * Look at using the {@link EventHandler} interface along with the pre-supplied BatchEventProcessor in the first 34 | * instance. 35 | *

36 | * An EventProcessor will generally be associated with a Thread for execution. 37 | */ 38 | public interface EventProcessor extends Runnable 39 | { 40 | /** 41 | * 获取事情处理器的Sequence(进度),每一个事件处理器有自己独立的Sequence, 42 | * Get a reference to the {@link Sequence} being used by this {@link EventProcessor}. 43 | * 44 | * @return reference to the {@link Sequence} for this {@link EventProcessor} 45 | */ 46 | Sequence getSequence(); 47 | 48 | /** 49 | * 通知事件处理器在完成本次消费之后,暂停下来。协作指令(类似中断) 50 | * {@link Thread#interrupt()} 51 | * Signal that this EventProcessor should stop when it has finished consuming at the next clean break. 52 | * It will call {@link SequenceBarrier#alert()} to notify the thread to check status. 53 | */ 54 | void halt(); 55 | 56 | /** 57 | * 查询事件处理器是否运行中 58 | */ 59 | boolean isRunning(); 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/YieldingWaitStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | 19 | /** 20 | * 该策略在尝试一定次数的自旋等待(空循环)之后使用尝试让出cpu。 21 | * 该策略将会占用大量的CPU资源(100%),但是比{@link BusySpinWaitStrategy}策略更容易在其他线程需要CPU时让出CPU。 22 | *

23 | * 它有着较低的延迟、较高的吞吐量,以及较高CPU占用率。当CPU数量足够时,可以使用该策略。 24 | * 25 | * Yielding strategy that uses a Thread.yield() for {@link com.lmax.disruptor.EventProcessor}s waiting on a barrier 26 | * after an initially spinning. 27 | *

28 | * This strategy will use 100% CPU, but will more readily give up the CPU than a busy spin strategy if other threads 29 | * require CPU resource. 30 | */ 31 | public final class YieldingWaitStrategy implements WaitStrategy 32 | { 33 | private static final int SPIN_TRIES = 100; 34 | 35 | @Override 36 | public long waitFor( 37 | final long sequence, Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier) 38 | throws AlertException, InterruptedException 39 | { 40 | long availableSequence; 41 | // 自旋尝试次数 42 | int counter = SPIN_TRIES; 43 | 44 | while ((availableSequence = dependentSequence.get()) < sequence) 45 | { 46 | // 当依赖的sequence还未完成对应序号的事件消费时,执行等待方法 47 | counter = applyWaitMethod(barrier, counter); 48 | } 49 | 50 | return availableSequence; 51 | } 52 | 53 | @Override 54 | public void signalAllWhenBlocking() 55 | { 56 | } 57 | 58 | private int applyWaitMethod(final SequenceBarrier barrier, int counter) 59 | throws AlertException 60 | { 61 | barrier.checkAlert(); 62 | 63 | // 当计数变为0时尝试让出CPU资源,避免大量占用CPU资源 64 | if (0 == counter) 65 | { 66 | Thread.yield(); 67 | } 68 | else 69 | { 70 | // 当计数大于0时,空循环。(有最高的响应性,但是对CPU占用太高) 71 | --counter; 72 | } 73 | 74 | return counter; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/WorkerPoolTest.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | import static org.hamcrest.CoreMatchers.is; 4 | import static org.junit.Assert.assertThat; 5 | 6 | import java.util.concurrent.Executor; 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.atomic.AtomicLong; 9 | 10 | import org.junit.Test; 11 | 12 | import com.lmax.disruptor.util.DaemonThreadFactory; 13 | 14 | 15 | public class WorkerPoolTest 16 | { 17 | @SuppressWarnings("unchecked") 18 | @Test 19 | public void shouldProcessEachMessageByOnlyOneWorker() throws Exception 20 | { 21 | Executor executor = Executors.newCachedThreadPool(DaemonThreadFactory.INSTANCE); 22 | WorkerPool pool = new WorkerPool( 23 | new AtomicLongEventFactory(), new FatalExceptionHandler(), 24 | new AtomicLongWorkHandler(), new AtomicLongWorkHandler()); 25 | 26 | RingBuffer ringBuffer = pool.start(executor); 27 | 28 | ringBuffer.next(); 29 | ringBuffer.next(); 30 | ringBuffer.publish(0); 31 | ringBuffer.publish(1); 32 | 33 | Thread.sleep(500); 34 | 35 | assertThat(ringBuffer.get(0).get(), is(1L)); 36 | assertThat(ringBuffer.get(1).get(), is(1L)); 37 | } 38 | 39 | @SuppressWarnings("unchecked") 40 | @Test 41 | public void shouldProcessOnlyOnceItHasBeenPublished() throws Exception 42 | { 43 | Executor executor = Executors.newCachedThreadPool(DaemonThreadFactory.INSTANCE); 44 | WorkerPool pool = new WorkerPool( 45 | new AtomicLongEventFactory(), new FatalExceptionHandler(), 46 | new AtomicLongWorkHandler(), new AtomicLongWorkHandler()); 47 | 48 | RingBuffer ringBuffer = pool.start(executor); 49 | 50 | ringBuffer.next(); 51 | ringBuffer.next(); 52 | 53 | Thread.sleep(1000); 54 | 55 | assertThat(ringBuffer.get(0).get(), is(0L)); 56 | assertThat(ringBuffer.get(1).get(), is(0L)); 57 | } 58 | 59 | private static class AtomicLongWorkHandler implements WorkHandler 60 | { 61 | @Override 62 | public void onEvent(AtomicLong event) throws Exception 63 | { 64 | event.incrementAndGet(); 65 | } 66 | } 67 | 68 | 69 | private static class AtomicLongEventFactory implements EventFactory 70 | { 71 | @Override 72 | public AtomicLong newInstance() 73 | { 74 | return new AtomicLong(0); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/support/FizzBuzzEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.EventHandler; 19 | import com.lmax.disruptor.util.PaddedLong; 20 | 21 | import java.util.concurrent.CountDownLatch; 22 | 23 | public final class FizzBuzzEventHandler implements EventHandler 24 | { 25 | private final FizzBuzzStep fizzBuzzStep; 26 | private final PaddedLong fizzBuzzCounter = new PaddedLong(); 27 | private long count; 28 | private CountDownLatch latch; 29 | 30 | public FizzBuzzEventHandler(final FizzBuzzStep fizzBuzzStep) 31 | { 32 | this.fizzBuzzStep = fizzBuzzStep; 33 | } 34 | 35 | public void reset(final CountDownLatch latch, final long expectedCount) 36 | { 37 | fizzBuzzCounter.set(0L); 38 | this.latch = latch; 39 | count = expectedCount; 40 | } 41 | 42 | public long getFizzBuzzCounter() 43 | { 44 | return fizzBuzzCounter.get(); 45 | } 46 | 47 | @Override 48 | public void onEvent(final FizzBuzzEvent event, final long sequence, final boolean endOfBatch) throws Exception 49 | { 50 | switch (fizzBuzzStep) 51 | { 52 | case FIZZ: 53 | if (0 == (event.getValue() % 3)) 54 | { 55 | event.setFizz(true); 56 | } 57 | break; 58 | 59 | case BUZZ: 60 | if (0 == (event.getValue() % 5)) 61 | { 62 | event.setBuzz(true); 63 | } 64 | break; 65 | 66 | case FIZZ_BUZZ: 67 | if (event.isFizz() && event.isBuzz()) 68 | { 69 | fizzBuzzCounter.set(fizzBuzzCounter.get() + 1L); 70 | } 71 | break; 72 | } 73 | 74 | if (latch != null && count == sequence) 75 | { 76 | latch.countDown(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerSetting.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.dsl; 17 | 18 | import com.lmax.disruptor.BatchEventProcessor; 19 | import com.lmax.disruptor.EventHandler; 20 | import com.lmax.disruptor.EventProcessor; 21 | import com.lmax.disruptor.ExceptionHandler; 22 | 23 | /** 24 | * 为EventHandler绑定异常处理的对象。 25 | * 26 | * A support class used as part of setting an exception handler for a specific event handler. 27 | * For example: 28 | *

disruptorWizard.handleExceptionsIn(eventHandler).with(exceptionHandler);
29 | * 30 | * @param the type of event being handled. 31 | */ 32 | public class ExceptionHandlerSetting 33 | { 34 | private final EventHandler eventHandler; 35 | private final ConsumerRepository consumerRepository; 36 | 37 | ExceptionHandlerSetting( 38 | final EventHandler eventHandler, 39 | final ConsumerRepository consumerRepository) 40 | { 41 | this.eventHandler = eventHandler; 42 | this.consumerRepository = consumerRepository; 43 | } 44 | 45 | /** 46 | * Specify the {@link ExceptionHandler} to use with the event handler. 47 | * 48 | * @param exceptionHandler the exception handler to use. 49 | */ 50 | @SuppressWarnings("unchecked") 51 | public void with(ExceptionHandler exceptionHandler) 52 | { 53 | final EventProcessor eventProcessor = consumerRepository.getEventProcessorFor(eventHandler); 54 | if (eventProcessor instanceof BatchEventProcessor) 55 | { 56 | ((BatchEventProcessor) eventProcessor).setExceptionHandler(exceptionHandler); 57 | consumerRepository.getBarrierFor(eventHandler).alert(); 58 | } 59 | else 60 | { 61 | throw new RuntimeException( 62 | "EventProcessor: " + eventProcessor + " is not a BatchEventProcessor " + 63 | "and does not support exception handlers"); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/FixedSequenceGroup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import java.util.Arrays; 19 | 20 | import com.lmax.disruptor.util.Util; 21 | 22 | /** 23 | * 固定Sequence数量的Sequence组 24 | * 用一个对象代替一组对象.(隐藏一些细节,eg:隐藏查找序号最小的Sequence) 25 | * 只支持获取,不支持更新 26 | * 27 | * Hides a group of Sequences behind a single Sequence 28 | */ 29 | public final class FixedSequenceGroup extends Sequence 30 | { 31 | private final Sequence[] sequences; 32 | 33 | /** 34 | * Constructor 35 | * 36 | * @param sequences the list of sequences to be tracked under this sequence group 37 | */ 38 | public FixedSequenceGroup(Sequence[] sequences) 39 | { 40 | this.sequences = Arrays.copyOf(sequences, sequences.length); 41 | } 42 | 43 | /** 44 | * 一组Sequence的进度就是Sequence最小的那个 45 | * 46 | * Get the minimum sequence value for the group. 47 | * 48 | * @return the minimum sequence value for the group. 49 | */ 50 | @Override 51 | public long get() 52 | { 53 | return Util.getMinimumSequence(sequences); 54 | } 55 | 56 | @Override 57 | public String toString() 58 | { 59 | return Arrays.toString(sequences); 60 | } 61 | 62 | /** 63 | * Not supported. 64 | */ 65 | @Override 66 | public void set(long value) 67 | { 68 | throw new UnsupportedOperationException(); 69 | } 70 | 71 | /** 72 | * Not supported. 73 | */ 74 | @Override 75 | public boolean compareAndSet(long expectedValue, long newValue) 76 | { 77 | throw new UnsupportedOperationException(); 78 | } 79 | 80 | /** 81 | * Not supported. 82 | */ 83 | @Override 84 | public long incrementAndGet() 85 | { 86 | throw new UnsupportedOperationException(); 87 | } 88 | 89 | /** 90 | * Not supported. 91 | */ 92 | @Override 93 | public long addAndGet(long increment) 94 | { 95 | throw new UnsupportedOperationException(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/NoOpEventProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import java.util.concurrent.atomic.AtomicBoolean; 19 | 20 | /** 21 | * 无操作的事件处理器。 22 | * 主要用于追踪数据发布的正确性的,对于测试来说是很有用的。 23 | * 24 | * No operation version of a {@link EventProcessor} that simply tracks a {@link Sequence}. 25 | *

26 | * This is useful in tests or for pre-filling a {@link RingBuffer} from a publisher. 27 | */ 28 | public final class NoOpEventProcessor implements EventProcessor 29 | { 30 | private final SequencerFollowingSequence sequence; 31 | private final AtomicBoolean running = new AtomicBoolean(false); 32 | 33 | /** 34 | * Construct a {@link EventProcessor} that simply tracks a {@link Sequence} object. 35 | * 36 | * @param sequencer to track. 37 | */ 38 | public NoOpEventProcessor(final RingBuffer sequencer) 39 | { 40 | sequence = new SequencerFollowingSequence(sequencer); 41 | } 42 | 43 | @Override 44 | public Sequence getSequence() 45 | { 46 | return sequence; 47 | } 48 | 49 | @Override 50 | public void halt() 51 | { 52 | running.set(false); 53 | } 54 | 55 | @Override 56 | public boolean isRunning() 57 | { 58 | return running.get(); 59 | } 60 | 61 | @Override 62 | public void run() 63 | { 64 | if (!running.compareAndSet(false, true)) 65 | { 66 | throw new IllegalStateException("Thread is already running"); 67 | } 68 | } 69 | 70 | /** 71 | * Sequence that follows (by wrapping) another sequence 72 | */ 73 | private static final class SequencerFollowingSequence extends Sequence 74 | { 75 | private final RingBuffer sequencer; 76 | 77 | private SequencerFollowingSequence(final RingBuffer sequencer) 78 | { 79 | super(Sequencer.INITIAL_CURSOR_VALUE); 80 | this.sequencer = sequencer; 81 | } 82 | 83 | @Override 84 | public long get() 85 | { 86 | return sequencer.getCursor(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/EventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 批事件处理器的事件处理回调接口 20 | * {@link BatchEventProcessor#processEvents()} 21 | * 22 | * Callback interface to be implemented for processing events as they become available in the {@link RingBuffer} 23 | * @param event implementation storing the data for sharing during exchange or parallel coordination of an event. 24 | * @see BatchEventProcessor#setExceptionHandler(ExceptionHandler) if you want to handle exceptions propagated out of the handler. 25 | */ 26 | public interface EventHandler 27 | { 28 | /** 29 | * {@link BatchEventProcessor}会批量的从RingBuffer中取出数据,然后逐个调用该方法进行处理 30 | * 31 | * 警告:如果在处理事件时抛出异常,而没有指定{@link ExceptionHandler}时,会导致BatchEventProcessor停止工作,可能导致死锁! 32 | * -> 系统默认的异常处理{@link FatalExceptionHandler}会将异常包装为RuntimeException重新抛出,直接退出循环吗,会导致死锁。 33 | * 34 | * 这样的好处是,你可以降低一些操作的消耗,可以攒到批量数据的结尾时进行一次操作。 35 | * 如IO操作,对写复制容器的操作(写入时尽量将多次写入合并为一次写入)。 36 | * Called when a publisher has published an event to the {@link RingBuffer}. The {@link BatchEventProcessor} will 37 | * read messages from the {@link RingBuffer} in batches, where a batch is all of the events available to be 38 | * processed without having to wait for any new event to arrive. This can be useful for event handlers that need 39 | * to do slower operations like I/O as they can group together the data from multiple events into a single 40 | * operation. Implementations should ensure that the operation is always performed when endOfBatch is true as 41 | * the time between that message an the next one is inderminate. 42 | * 43 | * @param event published to the {@link RingBuffer} 序号对应的事件数据 44 | * @param sequence of the event being processed 序号 45 | * @param endOfBatch flag to indicate if this is the last event in a batch from the {@link RingBuffer} 46 | * 是否是本次批处理的最后一个 47 | * @throws Exception if the EventHandler would like the exception handled further up the chain. 48 | */ 49 | void onEvent(T event, long sequence, boolean endOfBatch) throws Exception; 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/example/ThreeToOneDisruptor.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.example; 2 | 3 | 4 | import com.lmax.disruptor.EventFactory; 5 | import com.lmax.disruptor.EventHandler; 6 | import com.lmax.disruptor.dsl.Disruptor; 7 | import com.lmax.disruptor.util.DaemonThreadFactory; 8 | 9 | import java.util.concurrent.Executor; 10 | import java.util.concurrent.Executors; 11 | 12 | public class ThreeToOneDisruptor 13 | { 14 | public static class DataEvent 15 | { 16 | Object input; 17 | Object[] output; 18 | 19 | public DataEvent(int size) 20 | { 21 | output = new Object[size]; 22 | } 23 | 24 | public static final EventFactory FACTORY = new EventFactory() 25 | { 26 | @Override 27 | public DataEvent newInstance() 28 | { 29 | return new DataEvent(3); 30 | } 31 | }; 32 | } 33 | 34 | public static class TransformingHandler implements EventHandler 35 | { 36 | private final int outputIndex; 37 | 38 | public TransformingHandler(int outputIndex) 39 | { 40 | this.outputIndex = outputIndex; 41 | } 42 | 43 | @Override 44 | public void onEvent(DataEvent event, long sequence, boolean endOfBatch) throws Exception 45 | { 46 | // Do Stuff. 47 | event.output[outputIndex] = doSomething(event.input); 48 | } 49 | 50 | private Object doSomething(Object input) 51 | { 52 | // Do required transformation here.... 53 | return input; 54 | } 55 | } 56 | 57 | public static class CollatingHandler implements EventHandler 58 | { 59 | @Override 60 | public void onEvent(DataEvent event, long sequence, boolean endOfBatch) throws Exception 61 | { 62 | collate(event.output); 63 | } 64 | 65 | private void collate(Object[] output) 66 | { 67 | // Do required collation here.... 68 | } 69 | } 70 | 71 | public static void main(String[] args) 72 | { 73 | Executor executor = Executors.newFixedThreadPool(4); 74 | Disruptor disruptor = new Disruptor( 75 | DataEvent.FACTORY, 1024, DaemonThreadFactory.INSTANCE); 76 | 77 | TransformingHandler handler1 = new TransformingHandler(0); 78 | TransformingHandler handler2 = new TransformingHandler(1); 79 | TransformingHandler handler3 = new TransformingHandler(2); 80 | CollatingHandler collator = new CollatingHandler(); 81 | 82 | disruptor.handleEventsWith(handler1, handler2, handler3).then(collator); 83 | 84 | disruptor.start(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/TimeoutBlockingWaitStrategy.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import java.util.concurrent.locks.Condition; 5 | import java.util.concurrent.locks.Lock; 6 | import java.util.concurrent.locks.ReentrantLock; 7 | 8 | /** 9 | * 如果生产者生产速率不够,则阻塞式等待生产者一段时间。 10 | * 如果是等待依赖的其它消费者,则轮询式等待。 11 | * 12 | * 通过lock等待【生产者】发布数据,可以达到较低的cpu开销。 13 | * 注意:有坑!Disruptor框架并没有消费者之间的协调策略,而是通过简单的忙等策略实现的, 14 | * 因此,如果前置消费者消费较慢,而后置消费者速度较快,使用该策略反而会导致极大的开销, 15 | * 要解决问题可重写该实现,将第二阶段替换为 sleep 或 parkNanos(1); 16 | */ 17 | public class TimeoutBlockingWaitStrategy implements WaitStrategy 18 | { 19 | private final Lock lock = new ReentrantLock(); 20 | private final Condition processorNotifyCondition = lock.newCondition(); 21 | private final long timeoutInNanos; 22 | 23 | public TimeoutBlockingWaitStrategy(final long timeout, final TimeUnit units) 24 | { 25 | timeoutInNanos = units.toNanos(timeout); 26 | } 27 | 28 | @Override 29 | public long waitFor( 30 | final long sequence, 31 | final Sequence cursorSequence, 32 | final Sequence dependentSequence, 33 | final SequenceBarrier barrier) 34 | throws AlertException, InterruptedException, TimeoutException 35 | { 36 | long nanos = timeoutInNanos; 37 | 38 | long availableSequence; 39 | // 阻塞式等待生产者 40 | if (cursorSequence.get() < sequence) 41 | { 42 | lock.lock(); 43 | try 44 | { 45 | while (cursorSequence.get() < sequence) 46 | { 47 | barrier.checkAlert(); 48 | nanos = processorNotifyCondition.awaitNanos(nanos); 49 | if (nanos <= 0) 50 | { 51 | throw TimeoutException.INSTANCE; 52 | } 53 | } 54 | } 55 | finally 56 | { 57 | lock.unlock(); 58 | } 59 | } 60 | 61 | // 轮询式等待其它依赖的消费者消费完该事件 62 | while ((availableSequence = dependentSequence.get()) < sequence) 63 | { 64 | barrier.checkAlert(); 65 | } 66 | 67 | return availableSequence; 68 | } 69 | 70 | @Override 71 | public void signalAllWhenBlocking() 72 | { 73 | lock.lock(); 74 | try 75 | { 76 | processorNotifyCondition.signalAll(); 77 | } 78 | finally 79 | { 80 | lock.unlock(); 81 | } 82 | } 83 | 84 | @Override 85 | public String toString() 86 | { 87 | return "TimeoutBlockingWaitStrategy{" + 88 | "processorNotifyCondition=" + processorNotifyCondition + 89 | '}'; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/example/DynamiclyAddHandler.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.example; 2 | 3 | import com.lmax.disruptor.*; 4 | import com.lmax.disruptor.dsl.Disruptor; 5 | import com.lmax.disruptor.support.StubEvent; 6 | import com.lmax.disruptor.util.DaemonThreadFactory; 7 | 8 | import java.util.concurrent.CountDownLatch; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | 12 | public class DynamiclyAddHandler 13 | { 14 | private static class DynamicHandler implements EventHandler, LifecycleAware 15 | { 16 | private final CountDownLatch shutdownLatch = new CountDownLatch(1); 17 | 18 | @Override 19 | public void onEvent(final StubEvent event, final long sequence, final boolean endOfBatch) throws Exception 20 | { 21 | } 22 | 23 | @Override 24 | public void onStart() 25 | { 26 | 27 | } 28 | 29 | @Override 30 | public void onShutdown() 31 | { 32 | shutdownLatch.countDown(); 33 | } 34 | 35 | public void awaitShutdown() throws InterruptedException 36 | { 37 | shutdownLatch.await(); 38 | } 39 | } 40 | 41 | public static void main(String[] args) throws InterruptedException 42 | { 43 | ExecutorService executor = Executors.newCachedThreadPool(DaemonThreadFactory.INSTANCE); 44 | 45 | // Build a disruptor and start it. 46 | Disruptor disruptor = new Disruptor( 47 | StubEvent.EVENT_FACTORY, 1024, DaemonThreadFactory.INSTANCE); 48 | RingBuffer ringBuffer = disruptor.start(); 49 | 50 | // Construct 2 batch event processors. 51 | DynamicHandler handler1 = new DynamicHandler(); 52 | BatchEventProcessor processor1 = 53 | new BatchEventProcessor(ringBuffer, ringBuffer.newBarrier(), handler1); 54 | 55 | DynamicHandler handler2 = new DynamicHandler(); 56 | BatchEventProcessor processor2 = 57 | new BatchEventProcessor(ringBuffer, ringBuffer.newBarrier(processor1.getSequence()), handler2); 58 | 59 | // Dynamically add both sequences to the ring buffer 60 | ringBuffer.addGatingSequences(processor1.getSequence(), processor2.getSequence()); 61 | 62 | // Start the new batch processors. 63 | executor.execute(processor1); 64 | executor.execute(processor2); 65 | 66 | // Remove a processor. 67 | 68 | // Stop the processor 69 | processor2.halt(); 70 | // Wait for shutdown the complete 71 | handler2.awaitShutdown(); 72 | // Remove the gating sequence from the ring buffer 73 | ringBuffer.removeGatingSequence(processor2.getSequence()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/dsl/stubs/DelayedEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.dsl.stubs; 17 | 18 | import com.lmax.disruptor.EventHandler; 19 | import com.lmax.disruptor.LifecycleAware; 20 | import com.lmax.disruptor.support.TestEvent; 21 | 22 | import java.util.concurrent.BrokenBarrierException; 23 | import java.util.concurrent.CyclicBarrier; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | 26 | public class DelayedEventHandler implements EventHandler, LifecycleAware 27 | { 28 | private final AtomicBoolean readyToProcessEvent = new AtomicBoolean(false); 29 | private volatile boolean stopped = false; 30 | private final CyclicBarrier barrier; 31 | 32 | public DelayedEventHandler(CyclicBarrier barrier) 33 | { 34 | this.barrier = barrier; 35 | } 36 | 37 | public DelayedEventHandler() 38 | { 39 | this(new CyclicBarrier(2)); 40 | } 41 | 42 | @Override 43 | public void onEvent(final TestEvent entry, final long sequence, final boolean endOfBatch) throws Exception 44 | { 45 | waitForAndSetFlag(false); 46 | } 47 | 48 | public void processEvent() 49 | { 50 | waitForAndSetFlag(true); 51 | } 52 | 53 | public void stopWaiting() 54 | { 55 | stopped = true; 56 | } 57 | 58 | private void waitForAndSetFlag(final boolean newValue) 59 | { 60 | while (!stopped && !Thread.currentThread().isInterrupted() && 61 | !readyToProcessEvent.compareAndSet(!newValue, newValue)) 62 | { 63 | Thread.yield(); 64 | } 65 | } 66 | 67 | @Override 68 | public void onStart() 69 | { 70 | try 71 | { 72 | barrier.await(); 73 | } 74 | catch (InterruptedException e) 75 | { 76 | throw new RuntimeException(e); 77 | } 78 | catch (BrokenBarrierException e) 79 | { 80 | throw new RuntimeException(e); 81 | } 82 | } 83 | 84 | @Override 85 | public void onShutdown() 86 | { 87 | } 88 | 89 | public void awaitStart() throws InterruptedException, BrokenBarrierException 90 | { 91 | barrier.await(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/dsl/BasicExecutor.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.dsl; 2 | 3 | import com.lmax.disruptor.EventFactory; 4 | import com.lmax.disruptor.WaitStrategy; 5 | 6 | import java.lang.management.ManagementFactory; 7 | import java.lang.management.ThreadInfo; 8 | import java.lang.management.ThreadMXBean; 9 | import java.util.Queue; 10 | import java.util.concurrent.ConcurrentLinkedQueue; 11 | import java.util.concurrent.Executor; 12 | import java.util.concurrent.ThreadFactory; 13 | 14 | /** 15 | * 之所以不再推荐使用Executor的方式创建Disruptor,是因为外部的Executor可能是有界线程池, 16 | * 每一个{@link com.lmax.disruptor.EventProcessor} 都需要一个独立的线程。 17 | * 如果无法为EventProcessor创建足够多的线程,则会造成死锁(消费者总体进度为进度最小的那个---未运行的那些必定在列), 18 | * 导致生产者阻塞,生产者阻塞又导致其它消费者阻塞 --> 死锁。 19 | * {@link Disruptor#Disruptor(EventFactory, int, Executor)} 20 | * {@link Disruptor#Disruptor(EventFactory, int, Executor, ProducerType, WaitStrategy)} 21 | * 22 | * {@link BasicExecutor} 看似无界线程池,但实际是有界线程池,因为EventProcessor的数量是固定的。 23 | * 创建的线程数取决于EventProcessor的数量。 24 | * 25 | * 且该线程池不会用到工作队列{@link java.util.concurrent.BlockingQueue},而是通过{@link com.lmax.disruptor.RingBuffer} 26 | * 协调生产者与消费者之间的速度。 27 | */ 28 | public class BasicExecutor implements Executor 29 | { 30 | private final ThreadFactory factory; 31 | private final Queue threads = new ConcurrentLinkedQueue<>(); 32 | 33 | public BasicExecutor(ThreadFactory factory) 34 | { 35 | this.factory = factory; 36 | } 37 | 38 | /** 39 | * @param command 在disruptor中其实就是 {@link com.lmax.disruptor.EventProcessor} 40 | */ 41 | @Override 42 | public void execute(Runnable command) 43 | { 44 | final Thread thread = factory.newThread(command); 45 | if (null == thread) 46 | { 47 | throw new RuntimeException("Failed to create thread to run: " + command); 48 | } 49 | 50 | thread.start(); 51 | 52 | threads.add(thread); 53 | } 54 | 55 | @Override 56 | public String toString() 57 | { 58 | return "BasicExecutor{" + 59 | "threads=" + dumpThreadInfo() + 60 | '}'; 61 | } 62 | 63 | private String dumpThreadInfo() 64 | { 65 | final StringBuilder sb = new StringBuilder(); 66 | 67 | final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); 68 | 69 | for (Thread t : threads) 70 | { 71 | ThreadInfo threadInfo = threadMXBean.getThreadInfo(t.getId()); 72 | sb.append("{"); 73 | sb.append("name=").append(t.getName()).append(","); 74 | sb.append("id=").append(t.getId()).append(","); 75 | sb.append("state=").append(threadInfo.getThreadState()).append(","); 76 | sb.append("lockInfo=").append(threadInfo.getLockInfo()); 77 | sb.append("}"); 78 | } 79 | 80 | return sb.toString(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/LifecycleAwareTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import com.lmax.disruptor.support.StubEvent; 19 | import org.junit.Test; 20 | 21 | import java.util.concurrent.CountDownLatch; 22 | 23 | import static com.lmax.disruptor.RingBuffer.createMultiProducer; 24 | import static org.hamcrest.core.Is.is; 25 | import static org.junit.Assert.assertThat; 26 | 27 | public final class LifecycleAwareTest 28 | { 29 | private final CountDownLatch startLatch = new CountDownLatch(1); 30 | private final CountDownLatch shutdownLatch = new CountDownLatch(1); 31 | 32 | 33 | private final RingBuffer ringBuffer = createMultiProducer(StubEvent.EVENT_FACTORY, 16); 34 | private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(); 35 | private final LifecycleAwareEventHandler handler = new LifecycleAwareEventHandler(); 36 | private final BatchEventProcessor batchEventProcessor = 37 | new BatchEventProcessor(ringBuffer, sequenceBarrier, handler); 38 | 39 | @Test 40 | public void shouldNotifyOfBatchProcessorLifecycle() throws Exception 41 | { 42 | new Thread(batchEventProcessor).start(); 43 | 44 | startLatch.await(); 45 | batchEventProcessor.halt(); 46 | 47 | shutdownLatch.await(); 48 | 49 | assertThat(Integer.valueOf(handler.startCounter), is(Integer.valueOf(1))); 50 | assertThat(Integer.valueOf(handler.shutdownCounter), is(Integer.valueOf(1))); 51 | } 52 | 53 | private final class LifecycleAwareEventHandler implements EventHandler, LifecycleAware 54 | { 55 | private int startCounter = 0; 56 | private int shutdownCounter = 0; 57 | 58 | @Override 59 | public void onEvent(final StubEvent event, final long sequence, final boolean endOfBatch) throws Exception 60 | { 61 | } 62 | 63 | @Override 64 | public void onStart() 65 | { 66 | ++startCounter; 67 | startLatch.countDown(); 68 | } 69 | 70 | @Override 71 | public void onShutdown() 72 | { 73 | ++shutdownCounter; 74 | shutdownLatch.countDown(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/AggregateEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | /** 19 | * 20 | * 聚合EventHandler,这些EventHandler共用一个线程(EventProcessor),解决EventHandler需要大量线程的问题。 21 | * (普通的EventHandler都会被独立映射到一个EventProcessor,会分配一个独立的线程,线程创建压力较大) 22 | * 这些handler都会处理到所有的事件。 23 | * 24 | * 这些handler最终会在一个EventProcessor中,因此共享EventProcessor的序号(Sequence) 25 | * 26 | * 注意:任意一个EventHandler处理事件时或通知时出现异常,其他eventHandler就无法执行对应的方法 27 | * 28 | * An aggregate collection of {@link EventHandler}s that get called in sequence for each event. 29 | * 30 | * @param event implementation storing the data for sharing during exchange or parallel coordination of an event. 31 | */ 32 | public final class AggregateEventHandler 33 | implements EventHandler, LifecycleAware 34 | { 35 | private final EventHandler[] eventHandlers; 36 | 37 | /** 38 | * Construct an aggregate collection of {@link EventHandler}s to be called in sequence. 39 | * 40 | * @param eventHandlers to be called in sequence. 41 | */ 42 | @SafeVarargs 43 | public AggregateEventHandler(final EventHandler... eventHandlers) 44 | { 45 | this.eventHandlers = eventHandlers; 46 | } 47 | 48 | @Override 49 | public void onEvent(final T event, final long sequence, final boolean endOfBatch) 50 | throws Exception 51 | { 52 | for (final EventHandler eventHandler : eventHandlers) 53 | { 54 | // 任意一个出现异常就会打断其他EventHandler的事件处理 55 | eventHandler.onEvent(event, sequence, endOfBatch); 56 | } 57 | } 58 | 59 | @Override 60 | public void onStart() 61 | { 62 | for (final EventHandler eventHandler : eventHandlers) 63 | { 64 | if (eventHandler instanceof LifecycleAware) 65 | { 66 | ((LifecycleAware) eventHandler).onStart(); 67 | } 68 | } 69 | } 70 | 71 | @Override 72 | public void onShutdown() 73 | { 74 | for (final EventHandler eventHandler : eventHandlers) 75 | { 76 | if (eventHandler instanceof LifecycleAware) 77 | { 78 | ((LifecycleAware) eventHandler).onShutdown(); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/util/ThreadHints.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Gil Tene 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package com.lmax.disruptor.util; 17 | 18 | import java.lang.invoke.MethodHandle; 19 | import java.lang.invoke.MethodHandles; 20 | 21 | 22 | import static java.lang.invoke.MethodType.methodType; 23 | 24 | /** 25 | * 在JDK9的Thread中增加了{@code onSpinWait}方法,如果允许环境是JDK9的话,则在自旋等待时,尝试调用{@code onSpinWait}方法。 26 | * 27 | * This class captures possible hints that may be used by some 28 | * runtimes to improve code performance. It is intended to capture hinting 29 | * behaviours that are implemented in or anticipated to be spec'ed under the 30 | * {@link java.lang.Thread} class in some Java SE versions, but missing in prior 31 | * versions. 32 | */ 33 | public final class ThreadHints 34 | { 35 | private static final MethodHandle ON_SPIN_WAIT_METHOD_HANDLE; 36 | 37 | static 38 | { 39 | final MethodHandles.Lookup lookup = MethodHandles.lookup(); 40 | 41 | MethodHandle methodHandle = null; 42 | try 43 | { 44 | methodHandle = lookup.findStatic(Thread.class, "onSpinWait", methodType(void.class)); 45 | } 46 | catch (final Exception ignore) 47 | { 48 | } 49 | 50 | ON_SPIN_WAIT_METHOD_HANDLE = methodHandle; 51 | } 52 | 53 | private ThreadHints() 54 | { 55 | } 56 | 57 | /** 58 | * Indicates that the caller is momentarily unable to progress, until the 59 | * occurrence of one or more actions on the part of other activities. By 60 | * invoking this method within each iteration of a spin-wait loop construct, 61 | * the calling thread indicates to the runtime that it is busy-waiting. The runtime 62 | * may take action to improve the performance of invoking spin-wait loop constructions. 63 | */ 64 | public static void onSpinWait() 65 | { 66 | // Call java.lang.Thread.onSpinWait() on Java SE versions that support it. Do nothing otherwise. 67 | // This should optimize away to either nothing or to an inlining of java.lang.Thread.onSpinWait() 68 | if (null != ON_SPIN_WAIT_METHOD_HANDLE) 69 | { 70 | try 71 | { 72 | ON_SPIN_WAIT_METHOD_HANDLE.invokeExact(); 73 | } 74 | catch (final Throwable ignore) 75 | { 76 | } 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/support/StubEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.support; 17 | 18 | import com.lmax.disruptor.EventFactory; 19 | import com.lmax.disruptor.EventTranslatorTwoArg; 20 | 21 | public final class StubEvent 22 | { 23 | private int value; 24 | private String testString; 25 | public static final EventTranslatorTwoArg TRANSLATOR = 26 | new EventTranslatorTwoArg() 27 | { 28 | @Override 29 | public void translateTo(StubEvent event, long sequence, Integer arg0, String arg1) 30 | { 31 | event.setValue(arg0); 32 | event.setTestString(arg1); 33 | } 34 | }; 35 | 36 | public StubEvent(int i) 37 | { 38 | this.value = i; 39 | } 40 | 41 | public void copy(StubEvent event) 42 | { 43 | value = event.value; 44 | } 45 | 46 | public int getValue() 47 | { 48 | return value; 49 | } 50 | 51 | public void setValue(int value) 52 | { 53 | this.value = value; 54 | } 55 | 56 | public String getTestString() 57 | { 58 | return testString; 59 | } 60 | 61 | public void setTestString(final String testString) 62 | { 63 | this.testString = testString; 64 | } 65 | 66 | public static final EventFactory EVENT_FACTORY = new EventFactory() 67 | { 68 | public StubEvent newInstance() 69 | { 70 | return new StubEvent(-1); 71 | } 72 | }; 73 | 74 | @Override 75 | public int hashCode() 76 | { 77 | final int prime = 31; 78 | int result = 1; 79 | result = prime * result + value; 80 | return result; 81 | } 82 | 83 | @Override 84 | public boolean equals(Object obj) 85 | { 86 | if (this == obj) 87 | { 88 | return true; 89 | } 90 | if (obj == null) 91 | { 92 | return false; 93 | } 94 | if (getClass() != obj.getClass()) 95 | { 96 | return false; 97 | } 98 | StubEvent other = (StubEvent) obj; 99 | 100 | return value == other.value; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/dsl/stubs/StubThreadFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor.dsl.stubs; 17 | 18 | import com.lmax.disruptor.util.DaemonThreadFactory; 19 | import org.junit.Assert; 20 | 21 | import java.util.Collection; 22 | import java.util.concurrent.CopyOnWriteArrayList; 23 | import java.util.concurrent.ThreadFactory; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.concurrent.atomic.AtomicInteger; 26 | 27 | public final class StubThreadFactory implements ThreadFactory 28 | { 29 | private final DaemonThreadFactory threadFactory = DaemonThreadFactory.INSTANCE; 30 | private final Collection threads = new CopyOnWriteArrayList(); 31 | private final AtomicBoolean ignoreExecutions = new AtomicBoolean(false); 32 | private final AtomicInteger executionCount = new AtomicInteger(0); 33 | 34 | @Override 35 | public Thread newThread(final Runnable command) 36 | { 37 | executionCount.getAndIncrement(); 38 | Runnable toExecute = command; 39 | if(ignoreExecutions.get()) 40 | { 41 | toExecute = new NoOpRunnable(); 42 | } 43 | final Thread thread = threadFactory.newThread(toExecute); 44 | thread.setName(command.toString()); 45 | threads.add(thread); 46 | return thread; 47 | } 48 | 49 | public void joinAllThreads() 50 | { 51 | for (Thread thread : threads) 52 | { 53 | if (thread.isAlive()) 54 | { 55 | try 56 | { 57 | thread.interrupt(); 58 | thread.join(5000); 59 | } 60 | catch (InterruptedException e) 61 | { 62 | e.printStackTrace(); 63 | } 64 | } 65 | 66 | Assert.assertFalse("Failed to stop thread: " + thread, thread.isAlive()); 67 | } 68 | 69 | threads.clear(); 70 | } 71 | 72 | public void ignoreExecutions() 73 | { 74 | ignoreExecutions.set(true); 75 | } 76 | 77 | public int getExecutionCount() 78 | { 79 | return executionCount.get(); 80 | } 81 | 82 | private static final class NoOpRunnable implements Runnable 83 | { 84 | @Override 85 | public void run() 86 | { 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/ShutdownOnFatalExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | import com.lmax.disruptor.dsl.Disruptor; 4 | import com.lmax.disruptor.dsl.ProducerType; 5 | import com.lmax.disruptor.util.DaemonThreadFactory; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.util.Random; 11 | 12 | public class ShutdownOnFatalExceptionTest 13 | { 14 | 15 | private final Random random = new Random(); 16 | 17 | private final FailingEventHandler eventHandler = new FailingEventHandler(); 18 | 19 | private Disruptor disruptor; 20 | 21 | @SuppressWarnings("unchecked") 22 | @Before 23 | public void setUp() 24 | { 25 | disruptor = new Disruptor( 26 | new ByteArrayFactory(256), 1024, DaemonThreadFactory.INSTANCE, ProducerType.SINGLE, 27 | new BlockingWaitStrategy()); 28 | disruptor.handleEventsWith(eventHandler); 29 | disruptor.setDefaultExceptionHandler(new FatalExceptionHandler()); 30 | } 31 | 32 | @Test(timeout = 1000) 33 | public void shouldShutdownGracefulEvenWithFatalExceptionHandler() 34 | { 35 | disruptor.start(); 36 | 37 | byte[] bytes; 38 | for (int i = 1; i < 10; i++) 39 | { 40 | bytes = new byte[32]; 41 | random.nextBytes(bytes); 42 | disruptor.publishEvent(new ByteArrayTranslator(bytes)); 43 | } 44 | } 45 | 46 | @After 47 | public void tearDown() 48 | { 49 | disruptor.shutdown(); 50 | } 51 | 52 | private static class ByteArrayTranslator implements EventTranslator 53 | { 54 | 55 | private final byte[] bytes; 56 | 57 | ByteArrayTranslator(byte[] bytes) 58 | { 59 | this.bytes = bytes; 60 | } 61 | 62 | @Override 63 | public void translateTo(byte[] event, long sequence) 64 | { 65 | System.arraycopy(bytes, 0, event, 0, bytes.length); 66 | } 67 | } 68 | 69 | private static class FailingEventHandler implements EventHandler 70 | { 71 | private int count = 0; 72 | 73 | @Override 74 | public void onEvent(byte[] event, long sequence, boolean endOfBatch) throws Exception 75 | { 76 | // some logging 77 | count++; 78 | if (count == 3) 79 | { 80 | throw new IllegalStateException(); 81 | } 82 | } 83 | } 84 | 85 | private static class ByteArrayFactory implements EventFactory 86 | { 87 | private int eventSize; 88 | 89 | ByteArrayFactory(int eventSize) 90 | { 91 | this.eventSize = eventSize; 92 | } 93 | 94 | @Override 95 | public byte[] newInstance() 96 | { 97 | return new byte[eventSize]; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/lmax/disruptor/BlockingWaitStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 LMAX Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lmax.disruptor; 17 | 18 | import java.util.concurrent.locks.Condition; 19 | import java.util.concurrent.locks.Lock; 20 | import java.util.concurrent.locks.ReentrantLock; 21 | 22 | import com.lmax.disruptor.util.ThreadHints; 23 | 24 | /** 25 | * 阻塞等待策略。 26 | * 通过lock等待【生产者】发布数据,可以达到较低的cpu开销。 27 | * 注意:有坑!Disruptor框架并没有消费者之间的协调策略,而是通过简单的忙等策略实现的, 28 | * 因此,如果前置消费者消费较慢,而后置消费者速度较快,使用该策略反而会导致极大的开销, 29 | * 要解决问题可重写该实现,将第二阶段替换为 sleep 或 parkNanos(1); 30 | * 31 | * Blocking strategy that uses a lock and condition variable for {@link EventProcessor}s waiting on a barrier. 32 | *

33 | * This strategy can be used when throughput and low-latency are not as important as CPU resource. 34 | */ 35 | public final class BlockingWaitStrategy implements WaitStrategy 36 | { 37 | private final Lock lock = new ReentrantLock(); 38 | private final Condition processorNotifyCondition = lock.newCondition(); 39 | 40 | @Override 41 | public long waitFor(long sequence, Sequence cursorSequence, Sequence dependentSequence, SequenceBarrier barrier) 42 | throws AlertException, InterruptedException 43 | { 44 | // 确保生产者已生产者该数据,这期间可能阻塞 45 | long availableSequence; 46 | if (cursorSequence.get() < sequence) 47 | { 48 | lock.lock(); 49 | try 50 | { 51 | while (cursorSequence.get() < sequence) 52 | { 53 | barrier.checkAlert(); 54 | processorNotifyCondition.await(); 55 | } 56 | } 57 | finally 58 | { 59 | lock.unlock(); 60 | } 61 | } 62 | 63 | // 等待前驱消费者消费完对应的事件,这是实现消费者之间happens-before的关键 64 | while ((availableSequence = dependentSequence.get()) < sequence) 65 | { 66 | barrier.checkAlert(); 67 | ThreadHints.onSpinWait(); 68 | } 69 | 70 | return availableSequence; 71 | } 72 | 73 | @Override 74 | public void signalAllWhenBlocking() 75 | { 76 | lock.lock(); 77 | try 78 | { 79 | processorNotifyCondition.signalAll(); 80 | } 81 | finally 82 | { 83 | lock.unlock(); 84 | } 85 | } 86 | 87 | @Override 88 | public String toString() 89 | { 90 | return "BlockingWaitStrategy{" + 91 | "processorNotifyCondition=" + processorNotifyCondition + 92 | '}'; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/perftest/java/com/lmax/disruptor/immutable/CustomRingBuffer.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor.immutable; 2 | 3 | import com.lmax.disruptor.BatchEventProcessor; 4 | import com.lmax.disruptor.DataProvider; 5 | import com.lmax.disruptor.EventHandler; 6 | import com.lmax.disruptor.LifecycleAware; 7 | import com.lmax.disruptor.Sequencer; 8 | 9 | public class CustomRingBuffer implements DataProvider>, EventAccessor 10 | { 11 | private static final class AccessorEventHandler implements EventHandler>, LifecycleAware 12 | { 13 | private final EventHandler handler; 14 | private final LifecycleAware lifecycle; 15 | 16 | private AccessorEventHandler(EventHandler handler) 17 | { 18 | this.handler = handler; 19 | lifecycle = handler instanceof LifecycleAware ? (LifecycleAware) handler : null; 20 | } 21 | 22 | @Override 23 | public void onEvent(EventAccessor accessor, long sequence, boolean endOfBatch) throws Exception 24 | { 25 | this.handler.onEvent(accessor.take(sequence), sequence, endOfBatch); 26 | } 27 | 28 | @Override 29 | public void onShutdown() 30 | { 31 | if (null != lifecycle) 32 | { 33 | lifecycle.onShutdown(); 34 | } 35 | } 36 | 37 | @Override 38 | public void onStart() 39 | { 40 | if (null != lifecycle) 41 | { 42 | lifecycle.onStart(); 43 | } 44 | } 45 | } 46 | 47 | private final Sequencer sequencer; 48 | private final Object[] buffer; 49 | private final int mask; 50 | 51 | public CustomRingBuffer(Sequencer sequencer) 52 | { 53 | this.sequencer = sequencer; 54 | buffer = new Object[sequencer.getBufferSize()]; 55 | mask = sequencer.getBufferSize() - 1; 56 | } 57 | 58 | private int index(long sequence) 59 | { 60 | return (int) sequence & mask; 61 | } 62 | 63 | public void put(T e) 64 | { 65 | long next = sequencer.next(); 66 | buffer[index(next)] = e; 67 | sequencer.publish(next); 68 | } 69 | 70 | @SuppressWarnings("unchecked") 71 | @Override 72 | public T take(long sequence) 73 | { 74 | int index = index(sequence); 75 | 76 | T t = (T) buffer[index]; 77 | buffer[index] = null; 78 | 79 | return t; 80 | } 81 | 82 | @Override 83 | public EventAccessor get(long sequence) 84 | { 85 | return this; 86 | } 87 | 88 | public BatchEventProcessor> createHandler(final EventHandler handler) 89 | { 90 | BatchEventProcessor> processor = 91 | new BatchEventProcessor>( 92 | this, 93 | sequencer.newBarrier(), 94 | new AccessorEventHandler(handler)); 95 | sequencer.addGatingSequences(processor.getSequence()); 96 | 97 | return processor; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/test/java/com/lmax/disruptor/EventPollerTest.java: -------------------------------------------------------------------------------- 1 | package com.lmax.disruptor; 2 | 3 | import com.lmax.disruptor.EventPoller.PollState; 4 | import org.junit.Test; 5 | 6 | import java.util.ArrayList; 7 | 8 | import static org.hamcrest.core.Is.is; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class EventPollerTest 12 | { 13 | @Test 14 | @SuppressWarnings("unchecked") 15 | public void shouldPollForEvents() throws Exception 16 | { 17 | final Sequence gatingSequence = new Sequence(); 18 | final SingleProducerSequencer sequencer = new SingleProducerSequencer(16, new BusySpinWaitStrategy()); 19 | final EventPoller.Handler handler = new EventPoller.Handler() 20 | { 21 | public boolean onEvent(Object event, long sequence, boolean endOfBatch) throws Exception 22 | { 23 | return false; 24 | } 25 | }; 26 | 27 | final Object[] data = new Object[16]; 28 | final DataProvider provider = new DataProvider() 29 | { 30 | public Object get(long sequence) 31 | { 32 | return data[(int) sequence]; 33 | } 34 | }; 35 | 36 | final EventPoller poller = sequencer.newPoller(provider, gatingSequence); 37 | final Object event = new Object(); 38 | data[0] = event; 39 | 40 | assertThat(poller.poll(handler), is(PollState.IDLE)); 41 | 42 | // Publish Event. 43 | sequencer.publish(sequencer.next()); 44 | assertThat(poller.poll(handler), is(PollState.GATING)); 45 | 46 | gatingSequence.incrementAndGet(); 47 | assertThat(poller.poll(handler), is(PollState.PROCESSING)); 48 | } 49 | 50 | @Test 51 | public void shouldSuccessfullyPollWhenBufferIsFull() throws Exception 52 | { 53 | final ArrayList events = new ArrayList(); 54 | 55 | final EventPoller.Handler handler = new EventPoller.Handler() 56 | { 57 | public boolean onEvent(byte[] event, long sequence, boolean endOfBatch) throws Exception 58 | { 59 | events.add(event); 60 | return !endOfBatch; 61 | } 62 | }; 63 | 64 | EventFactory factory = new EventFactory() 65 | { 66 | @Override 67 | public byte[] newInstance() 68 | { 69 | return new byte[1]; 70 | } 71 | }; 72 | 73 | final RingBuffer ringBuffer = RingBuffer.createMultiProducer(factory, 4, new SleepingWaitStrategy()); 74 | 75 | final EventPoller poller = ringBuffer.newPoller(); 76 | ringBuffer.addGatingSequences(poller.getSequence()); 77 | 78 | int count = 4; 79 | 80 | for (byte i = 1; i <= count; ++i) 81 | { 82 | long next = ringBuffer.next(); 83 | ringBuffer.get(next)[0] = i; 84 | ringBuffer.publish(next); 85 | } 86 | 87 | // think of another thread 88 | poller.poll(handler); 89 | 90 | assertThat(events.size(), is(4)); 91 | } 92 | } 93 | --------------------------------------------------------------------------------