如何尽快获取锁列表中的锁?

How to acquire a lock among a list of locks as soon as possible?

我有这个极其简化的 class,运行锁定任务。锁是为了防止同一任务同时 运行 两次。 任务本身可以根据需要 运行 多次。

class Job {
  private Lock lock;
  
  // Constructor, getters, setters, etc. removed to stay short
  
  public boolean execute (int maxWaitTime) {
    if (lock.tryLock(maxWaitTime, TimeUnit.MILISECONDS)) {
      try {
        // do some lengthy job under the lock
      } finally {
        lock.unlock();
      }
    return true;
    }
  else return false;
  }
}

现在,假设我有这些工作的列表:

List<Job> jobs = ... ;

列表中的所有工作性质相同。我只想执行列表中的一个,暂时忽略所有其他的。 我只想执行第一个可用的任务,在当前持有锁之后等待尽可能少的任务(对应于当前 运行ning 的任务)。

过了一会儿,比方说 10 秒,如果所有作业仍然很忙,那么我放弃并且不执行任何作业(当然,实际上,在这种情况下会发生一些不同的事情)。

首先,我想到了这个:

for (Job job: jobs) {
  if (job.execute(10000)) return; // one job has been executed
}

然后意识到,如果我有 N 个工作,那么我可能会在放弃之前等待总共 10*N 秒而不是仅 10 秒,以防没有空闲工作并且 none 在此期间可用。

然后,我想到了这个:

long start = System.currentTimeMillis();
while (true) {
  for (Job job: jobs) {
    if (System.currentTimeMillis() -start > 10000) return; // give up after 10 seconds
    if (job.execute(0)) return; // one job has been executed
  }

我不是在等待 运行ning 任务,只是在 10 秒内执行第一个可用的任务,我会尽快执行,这很好。 但是,我在这里做 active wait,众所周知,这对一般性能来说很糟糕,应该避免。

我的第三次尝试是:

for (Job job: jobs) {
  if (job.execute(10000/jobs.size())) return; // one job has been executed
}

现在我最多等10秒。但这不是最佳解决方案。 假设我有 10 个工作,第 9 个是免费的,而前 8 个留在 运行ning。那样的话,我还是白白等了8秒,才找到空闲的执行。

我们可以做得更好吗?

作为一个偏好,我想要一个没有外部依赖的标准 Java 11 解决方案。我的示例的 Job class 在我的控制之下,因此如果需要我可以重构它。

感谢您的回答。

您需要尝试从 N 个不同的线程获取锁 10 秒。如果你成功地举起一个标志(你需要做到线程安全),如果标志已经举起释放当前锁,否则继续执行任务。

PS:N 是职位数。