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

如何让Semaphore按自定义优先级唤醒等待线程?

自定义优先级的Semaphore实现方案

你这个需求其实是要打破Semaphore默认的FIFO(公平模式)或随机唤醒(非公平模式)逻辑,换成按自定义优先级来选择唤醒线程的策略对吧?默认Semaphore的内部队列机制没法直接修改,所以我们得自己封装一个支持优先级的许可控制类,核心思路是用优先级队列来管理等待的线程,释放许可时优先唤醒最高优先级的线程。

具体实现步骤与代码示例

1. 封装带优先级的等待线程对象

首先我们需要一个类来包装线程和它的优先级,同时实现排序规则,让优先级高的线程能被优先取出:

static class PriorityThread implements Comparable<PriorityThread> {
    private final Thread thread;
    private final int priority;

    public PriorityThread(Thread thread, int priority) {
        this.thread = thread;
        this.priority = priority;
    }

    @Override
    public int compareTo(PriorityThread o) {
        // 这里定义优先级规则:数值越大,优先级越高
        // 如果需要数值小的优先级高,改成Integer.compare(this.priority, o.priority)即可
        return Integer.compare(o.priority, this.priority);
    }

    public Thread getThread() {
        return thread;
    }
}

2. 实现自定义的PrioritySemaphore类

这个类会管理许可数量,用线程安全的优先级队列维护等待线程,同时用锁保证操作的线程安全:

class PrioritySemaphore {
    private final int totalPermits;
    private int availablePermits;
    private final ReentrantLock lock = new ReentrantLock();
    private final PriorityBlockingQueue<PriorityThread> waitQueue = new PriorityBlockingQueue<>();

    public PrioritySemaphore(int totalPermits) {
        this.totalPermits = totalPermits;
        this.availablePermits = totalPermits;
    }

    // 带优先级的获取许可方法
    public void acquire(int priority) throws InterruptedException {
        lock.lock();
        try {
            // 如果有可用许可,直接获取
            if (availablePermits > 0) {
                availablePermits--;
                return;
            }
            // 没有许可,把当前线程包装后加入优先级队列
            PriorityThread currentPT = new PriorityThread(Thread.currentThread(), priority);
            waitQueue.add(currentPT);
            // 释放锁后挂起线程,避免占用锁导致其他线程无法操作
            lock.unlock();
            synchronized (currentPT) {
                currentPT.wait();
            }
            // 被唤醒后重新获取锁,继续后续流程
            lock.lock();
        } finally {
            lock.unlock();
        }
    }

    // 释放许可方法
    public void release() {
        lock.lock();
        try {
            availablePermits++;
            // 取出优先级最高的等待线程并唤醒
            PriorityThread highestPT = waitQueue.poll();
            if (highestPT != null) {
                synchronized (highestPT) {
                    highestPT.notify();
                }
            }
        } finally {
            lock.unlock();
        }
    }

    // 可选:获取当前可用许可数
    public int availablePermits() {
        lock.lock();
        try {
            return availablePermits;
        } finally {
            lock.unlock();
        }
    }
}

3. 在你的业务类中使用PrioritySemaphore

修改你的MyMathUtil2类,加入优先级字段,替换原有的Semaphore为我们自定义的PrioritySemaphore:

class MyMathUtil2 implements Runnable {
    double a;
    double b;
    String name;
    int threadPriority; // 新增线程优先级字段
    Thread t;
    private static final int MAX_COUNT = 2;
    // 替换为自定义的优先级Semaphore
    private static final PrioritySemaphore available = new PrioritySemaphore(MAX_COUNT);

    public MyMathUtil2(double a, double b, String name, int threadPriority) {
        this.a = a;
        this.b = b;
        this.name = name;
        this.threadPriority = threadPriority;
        this.t = new Thread(this, name);
        t.start();
    }

    @Override
    public void run() {
        try {
            // 传入优先级获取许可
            available.acquire(threadPriority);
            System.out.printf("线程【%s】开始执行,优先级:%d%n", name, threadPriority);
            // 模拟业务操作(比如计算、IO等)
            Thread.sleep(2000);
            double result = a + b;
            System.out.printf("线程【%s】执行完成,计算结果:%.1f%n", name, result);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.printf("线程【%s】被中断%n", name);
        } finally {
            // 释放许可
            available.release();
            System.out.printf("线程【%s】释放许可%n", name);
        }
    }

    // 测试用例
    public static void main(String[] args) {
        // 创建不同优先级的线程,观察执行顺序
        new MyMathUtil2(1.0, 2.0, "低优先级线程", 1);
        new MyMathUtil2(3.0, 4.0, "高优先级线程", 10);
        new MyMathUtil2(5.0, 6.0, "中优先级线程", 5);
        new MyMathUtil2(7.0, 8.0, "最高优先级线程", 15);
    }
}

实现关键点说明

  • 优先级队列的线程安全:用PriorityBlockingQueue来维护等待线程,它本身是线程安全的,不需要额外加锁保护队列的入队/出队操作,但许可计数的修改还是需要锁来保证原子性。
  • 线程挂起与唤醒:每个等待线程通过自己的PriorityThread对象作为锁来挂起/唤醒,避免了全局锁的竞争,同时保证唤醒的准确性。
  • 优先级规则可定制:在PriorityThread的compareTo方法里可以自由调整优先级的排序逻辑,比如改成按业务优先级、任务类型等排序,完全适配你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:18:22