All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.e6tech.elements.common.util.concurrent.DisruptorPool Maven / Gradle / Ivy

/*
 * Copyright 2015-2019 Futeh Kao
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.e6tech.elements.common.util.concurrent;

import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.WorkHandler;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import com.lmax.disruptor.util.DaemonThreadFactory;
import net.e6tech.elements.common.util.SystemException;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;

@SuppressWarnings("unchecked")
public class DisruptorPool {
    private DisruptorConfig config = new DisruptorConfig();
    Disruptor disruptor;

    public DisruptorPool() {
        start();
    }

    public DisruptorConfig getConfig() {
        return config;
    }

    public void setConfig(DisruptorConfig config) {
        this.config = config;
    }

    public Disruptor getDisruptor() {
        return disruptor;
    }

    public void setDisruptor(Disruptor disruptor) {
        this.disruptor = disruptor;
    }

    public void start() {
        disruptor = new Disruptor<>(Event::new, config.getBufferSize(), DaemonThreadFactory.INSTANCE,
                ProducerType.SINGLE, new YieldingWaitStrategy());
        WorkHandler handler = Event::handle;
        WorkHandler[] workers = new WorkHandler[config.getHandlerSize()];
        for (int i = 0; i < workers.length; i++) {
            workers[i] = handler;
        }
        disruptor.handleEventsWithWorkerPool(workers)
                .then((event, sequence, endOfBatch) -> event.clear());
        disruptor.start();
    }

    public RunnableWait run(Runnable runnable) {
        return run(runnable, null);
    }

    public RunnableWait run(Runnable runnable, Consumer exceptionHandler) {
        Result result = new Result<>();
        RingBuffer ringBuffer = disruptor.getRingBuffer();
        ringBuffer.publishEvent((event, sequence, buffer) -> {
            event.runnable = runnable;
            event.result = result;
            event.exceptionHandler = exceptionHandler;
        });

        return new RunnableWait(result);
    }

    public void runAsync(Runnable runnable) {
        runAsync(runnable, null);
    }

    public void runAsync(Runnable runnable, Consumer exceptionHandler) {
        RingBuffer ringBuffer = disruptor.getRingBuffer();
        ringBuffer.publishEvent((event, sequence, buffer) -> {
            event.runnable = runnable;
            event.exceptionHandler = exceptionHandler;
        });
    }

    public  CallableWait call(Callable callable) {
        return call(callable, null);
    }

    public  CallableWait call(Callable callable, Consumer exceptionHandler) {
        Result result = new Result();
        RingBuffer ringBuffer = disruptor.getRingBuffer();
        ringBuffer.publishEvent((event, sequence, buffer) -> {
            event.callable = callable;
            event.result = result;
            event.exceptionHandler = exceptionHandler;
        });

        return new CallableWait<>(result);
    }

    public static class Wait {
        Result result;

        Wait(Result result) {
            this.result = result;
        }

        protected void await(long timeout)  throws TimeoutException {
            long start = System.currentTimeMillis();
            boolean first = true;
            synchronized (result) {
                while (!result.done) {
                    if (!first && System.currentTimeMillis() - start > timeout) {
                        throw new TimeoutException();
                    }
                    if (first)
                        first = false;
                    try {
                        long wait = timeout - (System.currentTimeMillis() - start);
                        if (wait > 0)
                            result.wait(wait);
                        if (result.exception != null)
                            throw new SystemException(result.exception);

                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        throw new SystemException(e);
                    }
                }
            }
        }
    }

    public static class RunnableWait extends Wait {
        RunnableWait(Result result) {
            super(result);
        }

        public void complete(long timeout)  throws TimeoutException {
            await(timeout);
        }
    }

    public static class CallableWait extends Wait {
        CallableWait(Result result) {
            super(result);
        }

        public V complete(long timeout)  throws TimeoutException {
            await(timeout);
            return result.returnValue;
        }
    }

    private static class Result {
        private Exception exception;
        private V returnValue;
        private volatile boolean done = false;
    }

    private static class Event {
        private Result result;
        private Runnable runnable;
        private Callable callable;
        private Consumer exceptionHandler;

        void clear() {
            result = null;
            runnable = null;
            callable = null;
            exceptionHandler = null;
        }

        void handle() {
            if (runnable != null) {
                run();
            } else {
                call();
            }
            if (result != null) {
                synchronized (result) {
                    result.notifyAll();
                    result.done = true;
                }
            }
        }

        void run() {
            try {
                runnable.run();
            } catch (Exception ex) {
                if (exceptionHandler != null)
                    exceptionHandler.accept(ex);
                else if (result != null)
                    result.exception = ex;
            }
        }

        void call() {
            try {
                Object ret = callable.call();
                if (result != null)
                    result.returnValue = ret;
            } catch (Exception ex) {
                if (exceptionHandler != null)
                    exceptionHandler.accept(ex);
                else if (result != null)
                    result.exception = ex;
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy