You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带唯一元素的线程安全FIFO队列配合线程池实现调度文件复制的死锁修复问题

问题根因分析

现有代码死锁的核心原因是 worker 线程在持有全局锁 scheduledReplicationsLock 的情况下调用了 BlockingQueue.take(),队列为空时线程会一直阻塞在该方法上,且全程不释放锁,导致调度线程执行 add 方法时永远拿不到锁,无法添加新任务。

关于poll+休眠方案的评价

不推荐使用poll()加休眠的替代方案,这种方案属于折中妥协的dirty fix:休眠间隔设置过短会导致CPU空转浪费资源,设置过长会导致任务触发延迟,完全没有必要。

现有代码最小改动修复方案

你之前担心的「把take()移到同步块外会导致状态非原子更新」的问题实际不存在,核心逻辑是:
所有入队操作都是在持有全局锁的情况下原子完成「加入队列+ID写入queuedReplicationIds」的,只要任务还没有被worker线程更新状态,ID就一定留在queuedReplicationIds中,调度线程的重复提交判断逻辑不会失效。

修改后的worker线程run方法如下:

public void run() {
    while (true) {
        Replication replication = null;
        try {
            // 不持有锁的情况下阻塞等待任务,不会阻塞调度线程加任务
            replication = replicationQueue.take();
        } catch (InterruptedException e) {
            // 处理中断逻辑,比如退出线程
            Thread.currentThread().interrupt();
            break;
        }

        Long replicationId = replication.getId();
        synchronized (scheduledReplicationsLock) {
            // 把ID从待执行集合移到运行中集合
            queuedReplicationIds.remove(replicationId);
            runningReplicationIds.add(replicationId);
        }

        try {
            executeReplication(replication);
        } finally {
            // 【原来的代码漏了这个关键逻辑!】任务执行完成后必须移除运行中ID
            synchronized (scheduledReplicationsLock) {
                runningReplicationIds.remove(replicationId);
            }
        }
    }
}

同时补充add方法遗漏的返回值:

public boolean add(Replication replication) {
    synchronized (scheduledReplicationsLock) {
        if (queuedReplicationIds.contains(replication.id) || runningReplicationIds.contains(replication.id)) {
            return false;
        }
        replicationQueue.add(replication);
        queuedReplicationIds.add(replication.id);
        return true; // 补充遗漏的返回
    }
}
优化方案参考

如果想要进一步简化实现,可以做如下优化:

  • 合并两个ID集合为一个Map<Long, TaskState>,TaskState是枚举类:QUEUED/RUNNING,减少集合操作的冗余代码
  • 如果使用JDK并发包的ThreadPoolExecutor,可以重写beforeExecute和afterExecute方法来统一处理任务状态的更新,不用自己实现worker线程逻辑
  • 队列规模较小的场景下,不需要额外维护queuedReplicationIds,可以直接遍历队列判断ID是否存在,减少维护成本

内容的提问来源于stack exchange,提问作者Alan Evangelista

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 15:06:10