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

shz.core.accept.Acceptor Maven / Gradle / Ivy

package shz.core.accept;

import shz.core.ThreadHelp;
import shz.core.AccessibleCacheHelp;

import java.util.Collection;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public abstract class Acceptor {
    private final String threadName;
    private Executor executor;
    private final Lock lock;
    private final Condition sleep;
    private final Condition finish;
    private final Condition delay;
    private volatile boolean stop = true;
    private volatile boolean wait;

    protected Acceptor(String threadName) {
        this.threadName = threadName;
        lock = new ReentrantLock();
        sleep = lock.newCondition();
        finish = lock.newCondition();
        delay = lock.newCondition();
    }

    protected Acceptor() {
        this.threadName = AccessibleCacheHelp.identify(getClass());
        lock = new ReentrantLock();
        sleep = lock.newCondition();
        finish = lock.newCondition();
        delay = lock.newCondition();
    }

    protected long gapMillis() {
        return 0L;
    }

    protected long gapSleepMillis() {
        return 50L;
    }

    protected abstract boolean acceptable();

    protected void log(Throwable cause) {
        cause.printStackTrace();
    }

    protected abstract void execute();

    protected long sleepMicros() {
        return 0L;
    }

    protected boolean stoppable() {
        return false;
    }

    protected long finishMillis() {
        return 0L;
    }

    protected void finishCallback() {
    }

    protected long delayMicros() {
        return 5000L;
    }

    private void run() {
        while (!stop) {
            if (!lock.tryLock()) break;
            try {
                long idleMillis = 0L, gapMillis = gapMillis(), gapSleepMillis = gapSleepMillis();
                if (gapMillis > 0L) gapSleepMillis = Math.min(gapMillis, gapSleepMillis <= 0 ? 50L : gapSleepMillis);
                else gapSleepMillis = 0L;
                while (!stop) {
                    boolean acceptable = false;
                    try {
                        acceptable = acceptable();
                    } catch (Throwable e) {
                        log(e);
                    }
                    if (!acceptable) {
                        //无消费数据
                        if (gapSleepMillis == 0L || idleMillis >= gapMillis) break;
                        try {
                            TimeUnit.MILLISECONDS.sleep(gapSleepMillis);
                        } catch (InterruptedException ignored) {
                        }
                        //累计空闲时间
                        idleMillis += gapSleepMillis;
                        continue;
                    }
                    //重置空闲时间
                    idleMillis = 0L;

                    try {
                        //执行消费方法
                        execute();
                    } catch (Throwable e) {
                        log(e);
                    }

                    try {
                        long time = sleepMicros();
                        //消费睡眠
                        if (time > 0L) sleep.await(time, TimeUnit.MICROSECONDS);
                    } catch (Throwable e) {
                        log(e);
                    }
                }

                //判断是否结束线程任务
                if (!stop) try {
                    stop = stoppable();
                } catch (Throwable e) {
                    log(e);
                }

                if (!stop) {
                    wait = true;
                    if (!stop) {
                        long finishMillis = 100L;
                        long curMillis = System.currentTimeMillis();
                        try {
                            //当前没有可消费,等待被唤醒或等待超时
                            finishMillis = finishMillis();

                            //执行回调
                            finishCallback();
                        } catch (Throwable e) {
                            log(e);
                        }

                        if (finishMillis > 0L) {
                            long delta = finishMillis + curMillis - System.currentTimeMillis();
                            finishMillis = delta != 0L ? delta : 100L;
                        } else finishMillis = 0L;

                        if (wait) {
                            try {
                                if (finishMillis > 0L) finish.await(finishMillis, TimeUnit.MILLISECONDS);
                                else if (finishMillis == 0L) finish.await();
                            } catch (InterruptedException e) {
                                log(e);
                            }
                            wait = false;
                        }

                        long delayMicros = 0L;
                        try {
                            delayMicros = delayMicros();
                        } catch (Throwable e) {
                            log(e);
                        }

                        if (delayMicros > 0L && finishMillis < 0L) {
                            long delta = delayMicros + finishMillis;
                            delayMicros = delta > 0 ? delta : 100L;
                        }

                        try {
                            if (delayMicros > 0L) delay.await(delayMicros, TimeUnit.MICROSECONDS);
                        } catch (InterruptedException e) {
                            log(e);
                        }
                    }
                }
            } finally {
                lock.unlock();
            }
        }
    }

    protected final void accept() {
        if (!stop || !lock.tryLock()) return;
        try {
            if (!stop) return;
            stop = false;
            if (executor == null) executor = ThreadHelp.getExecutor(ThreadHelp.TPConfig
                    .of(threadName)
                    .tpType(ThreadHelp.TPType.SINGLE_THREAD_EXECUTOR)
                    .daemon(true)
                    .workQueue(new LinkedBlockingQueue<>(1)));
            executor.execute(this::run);
        } finally {
            lock.unlock();
        }
    }

    protected final void awaken() {
        if (!wait || !lock.tryLock()) return;
        try {
            if (!wait) return;
            wait = false;
            finish.signal();
        } catch (Throwable t) {
            log(t);
        } finally {
            lock.unlock();
        }
    }

    public final boolean isStop() {
        return stop;
    }

    public final synchronized void stop() {
        if (!stop) {
            stop = true;
            awaken();
        }
    }

    public final void push(T t) {
        if (offer(t)) {
            accept();
            awaken();
        }
    }

    protected abstract boolean offer(T t);

    public final void push(Collection dataset) {
        if (offer(dataset)) {
            accept();
            awaken();
        }
    }

    protected boolean offer(Collection dataset) {
        boolean flag = false;
        for (T t : dataset) {
            boolean offer = offer(t);
            if (!flag) flag = offer;
        }
        return flag;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy