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

com.xzchaoo.commons.syncexclusiveexecutor.SyncExclusiveExecutorImpl Maven / Gradle / Ivy

The newest version!
package com.xzchaoo.commons.syncexclusiveexecutor;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.xzchaoo.commons.basic.Ack;

/**
 * created at 2020/7/25
 *
 * @author xzchaoo
 */
public class SyncExclusiveExecutorImpl implements SyncExclusiveExecutor {
    private static final int                NO_TYPE       = -1;
    /**
     * Lock
     */
    private final        Lock               lock          = new ReentrantLock();
    /**
     * Wait map for every type
     */
    private final        Map waitMap       = new HashMap<>();
    /**
     * Limiter
     */
    private final        Limiter            limiter;
    /**
     * Executing type
     */
    private              int                executingType = NO_TYPE;
    /**
     * Max executed count before give up.
     */
    private              int                maxExecuted;
    /**
     * Max work-in-progress count
     */
    private              int                maxWip;
    /**
     * Release time to give up.
     */
    private              long               forceReleaseTime;
    /**
     * Executed count
     */
    private              int                executed;
    /**
     * Work in process count
     */
    private              int                wip;
    /**
     * Indicate whether other types has waiting
     */
    private              boolean            otherHasWaiting;

    private int waiting;

    public SyncExclusiveExecutorImpl(int maxExecuted, int maxWip, int maxTime) {
        this.limiter = new Limiter.Fixed(maxExecuted, maxWip, maxTime);
    }

    public SyncExclusiveExecutorImpl(Limiter limiter) {
        this.limiter = limiter;
    }

    @Override
    public Ack acquire(int type) {
        if (type < 0) {
            throw new IllegalStateException("type < 0");
        }
        lock.lock();
        try {
            ++waiting;
            Wait wait = waitMap.computeIfAbsent(type, Wait::new);
            for (; ; ) {
                if (executingType == NO_TYPE) {
                    Limit limit = limiter.limit(type);
                    this.executingType = type;
                    this.maxExecuted = limit.getMaxExecuted();
                    this.maxWip = limit.getMaxWip();
                    this.forceReleaseTime = limit.getMaxTime() > 0 ? (
                        System.currentTimeMillis() + limit.getMaxTime()) : 0;
                    ++executed;
                    ++wip;
                    break;
                } else if (executingType == type) {
                    if (!otherHasWaiting) {
                        ++executed;
                        ++wip;
                        break;
                    } else {
                        long now = System.currentTimeMillis();
                        // 20210430: 如果缺少 executed==0 的or条件, 那么可能会走进else分支
                        // 从而导致死锁, 这里加一个 executed == 0 条件可以让至少1个线程走进这个if分支, 从而不死锁
                        if (executed == 0 || executed < maxExecuted && (maxWip <= 0
                                || wip < maxWip) && (forceReleaseTime <= 0
                                || now < forceReleaseTime)) {
                            ++executed;
                            ++wip;
                            break;
                        } else {
                            if (wip == 0) {
                                switchToOther();
                            } else {
                                wait.await();
                            }
                        }
                    }
                } else {
                    otherHasWaiting = true;
                    wait.await();
                }
            }
        } finally {
            --waiting;
            lock.unlock();
        }
        return Ack.once(this::ack);
    }

    @Override
    public Stat stat() {
        Stat stat = new Stat();
        stat.setWaiting(waiting);
        stat.setWip(wip);
        stat.setExecutingType(executingType);
        stat.setExecuted(executed);
        stat.setForceReleaseTime(forceReleaseTime);
        return stat;
    }

    private void ack() {
        lock.lock();
        try {
            --wip;
            Wait wait = waitMap.get(executingType);
            // 如果当前类型有任务, 并且可以继续执行, 那么就signal一个等待着
            // 可以继续执行的条件是:
            // 1. 没有其他类型的任务正在等待
            // 2. 有其他任务正在等待, 但自己还可以继续执行

            if (wait.waiting > 0 && (!otherHasWaiting || (executed < maxExecuted
                && (forceReleaseTime <= 0
                || System.currentTimeMillis() < forceReleaseTime)))) {
                wait.condition.signal();
                // 否则当前类型已经达到要放弃执行的阶段了, 待wip达到0就切换到其他type
            } else if (wip == 0) {
                // 如果wip==0, 那么一定要记得清空状态, 否则下一次在添加任务, 那个任务无法执行!
                switchToOther();
            }
        } finally {
            lock.unlock();
        }
    }

    private void switchToOther() {
        int currentType = this.executingType;
        this.executed = 0;
        this.executingType = NO_TYPE;
        this.otherHasWaiting = false;
        this.forceReleaseTime = 0;
        for (Map.Entry e : waitMap.entrySet()) {
            if (e.getKey() != currentType && e.getValue().waiting > 0) {
                for (Map.Entry e2 : waitMap.entrySet()) {
                    if (!e.getKey().equals(e2.getKey())
                        && e2.getValue().waiting > 0) {
                        otherHasWaiting = true;
                        break;
                    }
                }
                Limit limit = limiter.limit(e.getKey());
                this.maxExecuted = limit.getMaxExecuted();
                this.maxWip = limit.getMaxWip();
                this.executingType = e.getKey();
                this.forceReleaseTime = limit.getMaxTime() > 0 ? (
                    System.currentTimeMillis() + limit.getMaxTime()) : 0;
                e.getValue().condition.signalAll();
                break;
            }
        }
        // 假设maxTime是1000ms, 这里sleep 1200ms, 并且去掉 executed==0 的判断就会导致死锁(走进else分支)
        // SleepUtils.sleepSilently(1200);
    }

    private class Wait {
        final int       type;
        final Condition condition = lock.newCondition();
        int waiting;

        Wait(int type) {
            this.type = type;
        }

        void await() {
            waiting++;
            try {
                condition.await();
            } catch (InterruptedException e) {
                throw new IllegalStateException("await interrupted", e);
            } finally {
                waiting--;
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy