Java - 信号量的优先级

Ľub*_*mír 9 java multithreading semaphore

我有多个线程访问外部资源 - 一个broswer.但是一次只能有一个线程访问它.所以,我正在使用信号量来同步它们.但是,一个线程从GUI获取输入然后访问浏览器以获得结果,应优先于其他线程,我不知道如何使用信号量来实现它.

我认为获取信号量后的每个线程都会检查队列中是否有优先级线程等待,如果是,则将其释放并再次等待.只有优先级线程在获取后才会释放它.

这是一个很好的解决方案还是我可以使用Java API中的其他任何东西?

And*_*gin 7

Java中没有同步原语允许您以您想要的方式为一个线程优先于其他线程.

但是你可以使用另一种方法来解决你的问题.不是同步线程,而是让它们生成小任务(例如,Runnable对象),并将这些任务放入PriorityBlockingQueue具有最高优先级的GUI线程的任务中.单个工作线程将从此队列轮询任务并执行它们.这将保证互斥和优先排序.

ThreadPoolExecutor接受阻塞队列的是特殊的构造函数.所以,你需要的就是这样一个执行器,它有一个单独的线程PriorityBlockingQueue<Runnable>.然后将您的任务提交给执行者,它将负责其余的工作.

如果您决定选择此方法,您可能会对此帖子感兴趣:如何使用ThreadPoolExecutor和自定义任务实现PriorityBlockingQueue


jta*_*orn 3

这是一个简单、不花哨的答案。这与读/写锁的工作原理类似,只是每个锁都具有独占访问权限(通常所有读取器并行进行)。请注意,它不使用Semaphore因为这几乎总是错误的使用结构。

public class PrioLock {
  private boolean _locked;
  private boolean _priorityWaiting;

  public synchronized void lock() throws InterruptedException {
    while(_locked || _priorityWaiting) {
      wait();
    }
    _locked = true;
  }

  public synchronized void lockPriority() throws InterruptedException {
    _priorityWaiting = true;
    try {
      while(_locked) {
          wait();
      }
      _locked = true;
    } finally {
      _priorityWaiting = false;
    }
  }

  public synchronized void unlock() {
    _locked = false;
    notifyAll();
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以像 java.util.concurrent 中的锁类型之一一样使用它:

普通线程:

_prioLock.lock();
try {
  // ... use resource here ...
} finally {
  _prioLock.unlock();
}
Run Code Online (Sandbox Code Playgroud)

“优先”线程:

_prioLock.lockPriority();
try {
  // ... use resource here ...
} finally {
  _prioLock.unlock();
}
Run Code Online (Sandbox Code Playgroud)

更新:

对有关“抢占式”线程交互的评论的回应:

从一般意义上来说,你不能这样做。您可以构建自定义功能,向锁定部分添加“暂停点”,这将允许低优先级线程让位于高优先级线程,但这将充满危险。

您实际上可以做的唯一一件事就是中断工作线程,使其退出锁定的代码块(假设您的工作代码响应中断)。这将允许高优先级线程更快地进行,但代价是低优先级线程丢失正在进行的工作(并且您可能还必须实现回滚逻辑)。

为了实现这一点,您需要:

  1. 锁定成功时记录“当前线程”。
  2. 在 中lockPriority(),如果找到则中断“当前线程”
  3. lock()实现/ (低优先级)调用之间的逻辑,unlock()以便:
    1. 它在合理的时间范围内响应中断
    2. 它在中断时实现任何必要的“回滚”代码
  4. 可能在/ (低优先级)调用之外实现“重试”逻辑,以便重新完成中断时丢失的任何工作lock()unlock()

  • @Duane - OP 表示只有一个优先线程(这被认为是一个“简单、没有多余装饰的答案”)。如果您想将其推广到可以拥有多个优先级线程的解决方案,那么,是的,_priorityWaiting 需要是一个计数器。您还可以有多个优先级级别或其他更奇特的变体...... (2认同)