Java多线程并发控制工具类

public class OperateBarrier {

    public static final String DROP_BARRIER = "DROP";
    public static final String WAIT_BARRIER = "WAIT";

    /**
     * Barriers
     */
    private static ConcurrentHashMap<String, Barrier> barrierMap = new ConcurrentHashMap<>();

    private static ConcurrentHashMap<String, Barrier> barrierDropMap = new ConcurrentHashMap<>();

    /**
     * Active time of barrier unit: second
     */
    private static final int BARRIER_EXIST_IN_SECONDS = 10;

    private static final Lock lock = new ReentrantLock();


    public static <R> R operate(Supplier<R> operate) {
        try {
            lock.lock();
            // 同步执行
            return operate.get();
        } finally {
            lock.unlock();
        }
    }

    public static <R> R operateDropOrWait(String strategy, String operateId, Supplier<R> operateHandel) {
        if (DROP_BARRIER.equals(strategy)) {
            return operateDrop(operateId, operateHandel);
        } else if (WAIT_BARRIER.equals(strategy)) {
            return operateWait(operateId, operateHandel);
        } else {
            return operate(operateHandel);
        }
    }


    /**
     * 同一个key、不能重复执行,如果存在重复的,默认5s; 5内只允许一个key执行,如果等待5s后,依旧没有没有获取到锁,就丢弃;
     * 采用 semaphore 实现
     * @param operateId
     * @param operate
     * @return
     * @param <R>
     */
    public static <R> R operateDrop(String operateId, Supplier<R> operate) {

        Barrier keyLock = barrierDropMap.computeIfAbsent(operateId, k -> new Barrier(operateId));
        // 尝试获取许可,最多等待5秒
        boolean acquired = false;
        R result = null;
        try {
            acquired = keyLock.semaphore.tryAcquire(5, TimeUnit.SECONDS);
            if (!acquired) {
                // 超时后没有获得许可,直接返回
                System.out.println("Timeout waiting for semaphore, task not executed by " + Thread.currentThread().getName() + " with key " + operateId);
                return null;
            }
            keyLock.barrierLock.lock();
            try {
                while (keyLock.isRunning.get()) {
                    // 如果已经有线程在执行,当前线程等待
                    keyLock.enQueueCondition.await();
                }
                keyLock.isRunning.set(true);
                try {
                    // 执行任务
                    result = operate.get();
                } finally {
                    // 任务执行完毕,重置标志位并唤醒等待的线程
                    keyLock.isRunning.set(false);
                    keyLock.enQueueCondition.signal(); // 只唤起一个线程
                }
            } finally {
                keyLock.barrierLock.unlock();
            }
        } catch (InterruptedException e) {
            log.info("operateDrop exception:{}", e);
            System.out.println("Thread interrupted ");
            Thread.currentThread().interrupt();
        } finally {
            if (acquired) {
                keyLock.semaphore.release();
            }
            if(!keyLock.semaphore.hasQueuedThreads() && !keyLock.isRunning.get()){
                // 任务执行完成后移除operateId对应的Barrier对象
                log.info("barrierDropMap release key:{}",operateId);
                barrierDropMap.remove(operateId);
            }
        }
        return result;
    }


    /**
     * 等待过期后,如果还没执行完,放弃执行,数据交给下一个,默认是同一个key、等待10秒、如果10秒没有释放,数据就不会执行
     * @param operateId
     * @param operate
     * @return
     * @param <R>
     */
    public static <R> R operateWait(String operateId, Supplier<R> operate) {
        Barrier barrier = barrierMap.computeIfAbsent(operateId, key -> new Barrier(operateId));
        boolean signal = inQueue(barrier);
        try {
            // 同步执行
            return operate.get();
        } finally {
            deQueue(barrier, signal);
        }
    }

    /**
     * 功能: 将当前线程加入队列,并判断是否要等待。
     * 步骤详解:
     * - 获取 barrier.barrierLock 的锁,确保对共享资源的安全访问。
     * - 检查当前 Barrier 中的在队列数量,如果大于0,表示有其他线程正在处理,则当前线程需要等待。
     * - 使用 await 方法将当前线程挂起,最多等待 BARRIER_EXIST_IN_SECONDS 秒。
     * - 增加在队列中的计数器。
     * - 释放锁。
     * @param barrier
     * @return
     */
    private static boolean inQueue(Barrier barrier) {
        boolean signal = true;
        barrier.barrierLock.lock();
        try {
            // 如果存在队列数,那么当前数据等待10秒,
            if (barrier.enQueueCount.get() > 0) {
                // 当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态
                signal = barrier.enQueueCondition.await(BARRIER_EXIST_IN_SECONDS, TimeUnit.SECONDS);
            }
            barrier.enQueueCount.incrementAndGet();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            //Ignore
        } finally {
            barrier.barrierLock.unlock();
        }
        return signal;
    }

    /**
     * 功能: 从队列中移除当前操作,并处理线程的信号逻辑。
     * 步骤详解:
     * - 获取 barrier.barrierLock 的锁。
     * - 检查在队列中的计数器,如果大于0,并且信号为真,释放一个被阻塞的线程。
     * - 减少在队列中的计数器。
     * - 如果没有任何线程在等待该条件,则从 barrierMap 中移除该 Barrier 对象。
     * - 释放锁。
     * @param barrier
     * @param signal
     */
    private static void deQueue(Barrier barrier, boolean signal) {
        barrier.barrierLock.lock();
        try {
            if (barrier.enQueueCount.get() > 0) {
                if (signal) {
                    // 释放阻塞的线程
                    barrier.enQueueCondition.signal();
                }
                barrier.enQueueCount.decrementAndGet();
            }
            if (!barrier.barrierLock.hasWaiters(barrier.enQueueCondition)) {
                barrierMap.remove(barrier.id);
            }
        } finally {
            barrier.barrierLock.unlock();
        }
    }

    private static class Barrier {

        private final ReentrantLock barrierLock;
        /**
         * In queue
         */
        private final Condition enQueueCondition;

        private String id;

        private final AtomicInteger enQueueCount = new AtomicInteger(0);

        private final Semaphore semaphore = new Semaphore(1);

        private final AtomicBoolean isRunning = new AtomicBoolean(false);

        Barrier(String id) {
            this.id = id;
            barrierLock = new ReentrantLock();
            enQueueCondition = barrierLock.newCondition();
        }
    }


    public static void main(String[] args) {

        CountDownLatch countDownLatch = new CountDownLatch(100);
        for (int i = 1; i < 1000; i++) {
            String finalNum = "AAA" + "_";
            new Thread(() -> {
                // 5 S,释放
                String result = OperateBarrier.operateDrop(finalNum, () -> {
                    try {
                        System.out.println(Thread.currentThread().getName() + "   ->    " + finalNum);
                        int i1 = RandomUtils.nextInt(1, 7) * 1000;
                        System.out.println(Thread.currentThread().getName() + "sleep " + i1 + "; time" + System.currentTimeMillis());
                        Thread.sleep(i1);
                        return "123";
                    } catch (InterruptedException exception) {
                        exception.printStackTrace();
                    }
                    return finalNum;
                });
                System.out.println(Thread.currentThread().getName() + "原创“result ------------> :" + result);
            }).start();
        }

        for (int i = 0; i < 100; i++) {
            countDownLatch.countDown();
            try {
                Thread.sleep(1000);
                System.out.println("---原创https://blog.csdn.net/Alecor----countDown count:" + countDownLatch.getCount() + "barrierDropMap size:" + barrierDropMap.size());
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }

        System.out.println("endendendendendend");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值