简体   繁体   English

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

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

I have this extremely simplified class, running a task under a lock.我有这个极其简化的类,在锁定下运行任务。 The lock is there to prevent the same task to run concurrently twice.锁是为了防止同一个任务同时运行两次。 The task itself can be run as many times as needed.任务本身可以根据需要运行多次。

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;
  }
}

Now, let's say that I have a list of these jobs:现在,假设我有这些工作的列表:

List<Job> jobs = ... ;

All the jobs in the list are of the same nature.列表中的所有作业都具有相同的性质。 I would like to execute only a single one from the list, ignoring all others for the moment.我只想执行列表中的一个,暂时忽略所有其他人。 I want to execute the first available task only, waiting as few as possible after currently held locks (corresponding to tasks currently running).我只想执行第一个可用的任务,在当前持有的锁(对应于当前正在运行的任务)后等待尽可能少。

After a while, let's say 10 seconds, if all jobs are still busy, then I give up and don't execute any (in reality, of course, something different happens in that case).一段时间后,假设 10 秒,如果所有作业仍然很忙,那么我放弃并且不执行任何作业(当然,在这种情况下会发生不同的事情)。

First, I came up with this:首先,我想出了这个:

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

And then realised that, if I had N jobs, then I might end up waiting a total of 10*N seconds instead of only 10 before giving up, in case there's no free job and none become available in the meantime.然后意识到,如果我有 N 个工作,那么我最终可能会等待总共10*N秒而不是仅仅 10 秒才放弃,以防在此期间没有空闲工作并且没有可用工作。

Then, I thought about this:然后,我想到了这个:

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
  }

I'm not waiting for a running task and just execute the first available within the 10 seconds, and I'm doing it as quick as possible, that's fine.我不是在等待正在运行的任务,而是在 10 秒内执行第一个可用的任务,而且我正在尽可能快地执行,这很好。 However, I'm doing active wait here, which is known to be terrible for general performances and should be avoided.但是,我在这里做主动等待,众所周知,这对一般表演来说很糟糕,应该避免。

My third attempt is:我的第三次尝试是:

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

Now I wait at most 10 seconds as desired.现在我根据需要最多等待 10 秒。 But it isn't the most optimal solution.但这不是最佳解决方案。 Let's say I have 10 jobs, the 9th is free, while the first 8 stay running.假设我有 10 个工作,第 9 个是免费的,而前 8 个保持运行。 In that case, I will still wait uselessly for 8 seconds before finding the free one and execute it.在那种情况下,我仍然会无用地等待 8 秒钟,然后才能找到空闲的并执行它。

Can we do better ?我们能做得更好吗?

As a preference, I would like a standard Java 11 solution without external dependency.作为偏好,我想要一个没有外部依赖的标准 Java 11 解决方案。 The Job class of my example is under my control, so I can refactor it if needed.我的示例的 Job 类在我的控制之下,因此我可以在需要时对其进行重构。

Thank you for your answers.谢谢您的回答。

What you need is to try to acquire lock for 10 seconds from N different threads.您需要的是尝试从N不同的线程获取 10 秒的锁。 If you succeed in it raise a flag (you need to do it thread safe) and if flag already raised release current lock otherwise proceed to execute task.如果你成功,它会提升一个标志(你需要做线程安全),如果标志已经被提升释放当前锁,否则继续执行任务。

PS: N is number of jobs. PS: N是作业数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM