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

如何避免使用锁原语,保证队列中同一时间仅运行一个任务?

无锁实现单任务串行执行的队列方案

原代码通过synchronized锁控制队列的任务提交与续跑逻辑,虽然能保证同一时刻仅一个任务执行,但锁竞争和线程切换会带来额外性能开销。可以通过原子类+无锁线程安全队列的组合完全替代锁原语,实现相同语义且性能更优。

核心改造思路

  • 用AtomicBoolean替代普通boolean维护running状态,通过CAS操作实现无锁的状态抢占
  • 将非线程安全的ArrayDeque替换为无锁线程安全队列ConcurrentLinkedQueue,避免队列操作的线程安全问题
  • 调整append和resume方法逻辑,用原子操作替代同步块

改造后的代码

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.Getter;

public class Queue {
    public static final Executor EXECUTOR = new Executor(16, 16);

    @Getter
    private final long id;
    @Getter
    private final String name;
    @Getter
    private final int capacity;

    private final Queue<Command> queue;
    private final AtomicBoolean running = new AtomicBoolean(false);
    private final AtomicBoolean destroy = new AtomicBoolean(false);


    public Queue(long id, String name, int capacity) {
        this.id = id;
        this.name = name;
        this.capacity = capacity;
        this.queue = new ConcurrentLinkedQueue<>();
    }

    public boolean append(Command command) {
        command.setQueue(this);
        // 队列已销毁,直接拒绝任务
        if (destroy.get()) {
            return false;
        }
        // CAS抢占执行权:当前无任务运行时,标记为运行中并提交任务
        if (running.compareAndSet(false, true)) {
            EXECUTOR.execute(command);
            return true;
        }
        // 抢占失败,尝试将任务加入队列(队列满则返回false)
        return queue.offer(command);
    }

    protected void resume() {
        // 队列已销毁,标记为无任务运行并返回
        if (destroy.get()) {
            running.set(false);
            return;
        }
        Command command = queue.poll();
        if (command != null) {
            // 队列还有任务,直接提交执行
            EXECUTOR.execute(command);
        } else {
            // 队列空了,标记为无任务运行,允许新任务直接抢占
            running.set(false);
        }
    }

    public boolean isDestroy() {
        return destroy.get();
    }

    public void setDestroy(boolean destroy) {
        this.destroy.set(destroy);
    }
}

// Executor类保持原逻辑无需修改

逻辑说明

  • append方法:通过running.compareAndSet(false, true)原子性抢占执行权,成功则直接提交任务;失败则将任务加入队列等待
  • resume方法:任务执行完成后触发,从队列取出下一个任务提交;队列空时将running置为false,让后续新任务可以直接抢占执行权
  • 线程安全保障:AtomicBoolean的CAS操作和ConcurrentLinkedQueue的无锁实现,确保所有并发操作线程安全,无需依赖synchronized锁

这种方案完全避免了锁原语的使用,消除了锁竞争带来的线程切换开销,同时严格保证同一队列中仅一个任务运行至完成的语义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 18:46:14