在java中,在某些条件下阻止线程

在java中,在某些条件下阻止线程,java,java.util.concurrent,Java,Java.util.concurrent,也许这真是个愚蠢的问题,但请听我说完。我有一个用例,在这个用例中,我得到许多并发的请求来为一个特定的输入日期做一些事情。如果在同一输入日期收到两个并发请求,则在前一个请求完全完成之前(出于充分理由),后续请求不应继续。使用标准java.util.concurrent组件实现此目的的最佳方法是什么?我最初的想法是建立一个锁工厂,它将出售锁并保存一份副本,以表明它正在使用,并等待后续请求()。然而,这似乎有很多锅炉板的代码-任何简单的把戏,是逃避我 提前谢谢 在我看来,您必须将请求排队,然后一次处理

也许这真是个愚蠢的问题,但请听我说完。我有一个用例,在这个用例中,我得到许多并发的请求来为一个特定的输入日期做一些事情。如果在同一输入日期收到两个并发请求,则在前一个请求完全完成之前(出于充分理由),后续请求不应继续。使用标准java.util.concurrent组件实现此目的的最佳方法是什么?我最初的想法是建立一个锁工厂,它将出售锁并保存一份副本,以表明它正在使用,并等待后续请求()。然而,这似乎有很多锅炉板的代码-任何简单的把戏,是逃避我


提前谢谢

在我看来,您必须将请求排队,然后一次处理一个请求。因此,也许java.util.concurrent中的阻塞队列?

在我看来,您必须将请求排队,并一次处理一个请求。因此,可能是来自java.util.concurrent的BlockingQueue?

您需要创建一个ThreadPoolExecutor来在多个线程中执行请求。此外,您还需要有一个输入日期列表,这些日期现在已被处理。此列表应具有同步访问器和putIfAbsent方法。在将任务发送到队列之前,请检查其输入日期现在是否未被处理。如果现在已处理,请将此任务移动到队列末尾,然后尝试运行下一个任务。任务完成后,从列表中删除其输入日期。

您需要创建一个ThreadPoolExecutor以在多个线程中执行请求。此外,您还需要有一个输入日期列表,这些日期现在已被处理。此列表应具有同步访问器和putIfAbsent方法。在将任务发送到队列之前,请检查其输入日期现在是否未被处理。如果现在已处理,请将此任务移动到队列末尾,然后尝试运行下一个任务。任务完成后,将其输入日期从列表中删除。

我假设您已经有了一个系统,在该系统中,线程可以接收输入请求并处理它们,而不会丢失或复制任何请求,从而解决任何锁定问题。然后,您只需要每个线程在某个地方记录它当前正在处理的事情的输入日期。当一个线程检查一个输入请求时,它首先检查日期,查看当前是否有任何具有该日期的请求正在被处理,如果有,那么它会将该请求留在队列中并接受下一个请求


您将需要一定量的锁定,以确保“当前正在处理条目”在测试时不处于更新过程中。

我假设您已经有了一个系统,在该系统中,线程可以接收输入请求并处理它们,而不会丢失或复制任何内容,从而解决任何锁定问题。然后,您只需要每个线程在某个地方记录它当前正在处理的事情的输入日期。当一个线程检查一个输入请求时,它首先检查日期,查看当前是否有任何具有该日期的请求正在被处理,如果有,那么它会将该请求留在队列中并接受下一个请求


您需要一定量的锁定,以确保“当前正在处理条目”在测试时不处于更新过程中。

您可以对日期时间的各个锁定进行散列

private static final ConcurrentMap<Long,Lock> dateLock = new ConcurrentHashMap<Long,Lock>();

public static Lock getLock(Date date){
  Lock lock = dateLock.get(date.getTime());  
  if(lock == null){
    Lock lock = new ReentrantLock();  
    Lock temp =dateLock.putIfAbsent(lock); 
    lock = temp == null ? lock : temp;
  }
 return lock;
}

以此类推

您可以对日期时间的各个锁进行散列

private static final ConcurrentMap<Long,Lock> dateLock = new ConcurrentHashMap<Long,Lock>();

public static Lock getLock(Date date){
  Lock lock = dateLock.get(date.getTime());  
  if(lock == null){
    Lock lock = new ReentrantLock();  
    Lock temp =dateLock.putIfAbsent(lock); 
    lock = temp == null ? lock : temp;
  }
 return lock;
}

诸如此类

您正在寻找的简单技巧是线程池“按顺序处理”模式

您正在寻找的简单技巧是线程池“按顺序处理”模式

你能把所有的请求排队,一次处理一个吗?如果性能合理,队列可以解决许多并发问题。您是否需要为同一输入日期“按到达顺序”(公平)执行排队任务,或者下一个运行哪个任务并不重要,只要它们没有两个同时运行?@user949300将所有请求排队在这里不是一个可行的选择。请求是实时发出的。@seh大致相同的顺序(虽然不是严格意义上的)注意,使用锁意味着使用队列(或者,如果您愿意,使用一组等待者)。否则调度程序如何知道哪些线程被阻塞在哪些锁上,等待唤醒?当然,每个锁有一个队列,这可能是您可以接受的。您能将所有请求排队,然后一次处理一个请求吗?如果性能合理,队列可以解决许多并发问题。您是否需要为同一输入日期“按到达顺序”(公平)执行排队任务,或者下一个运行哪个任务并不重要,只要它们没有两个同时运行?@user949300将所有请求排队在这里不是一个可行的选择。请求是实时发出的。@seh大致相同的顺序(虽然不是严格意义上的)注意,使用锁意味着使用队列(或者,如果您愿意,使用一组等待者)。否则调度程序如何知道哪些线程被阻塞在哪些锁上,等待唤醒?当然,每个锁有一个队列,这可能是您可以接受的。只有当请求来自同一日期时,才应该排队。否则,请求应并行处理。仅当请求来自同一日期时,才应将其排队。否则请求应该并行处理。使用ConcurrentMap也应该做到这一点,对吗?我选择这个答案,因为它还清楚地提到了如何在不需要额外队列的情况下实现争用线程之间的阻塞,尽管DJClayworth也很接近。谢谢大家。@Kilokahn可能会的,不过我尽量避免使用/假设Date类中除了
getTime()
之外的很多内容。请注意,使用这种方法,没有安全的方法来清除任何以前绑定的锁实例。这是一个“只增长”的解决方案。清除锁需要在更高级别上锁定(可能在映射本身上),这取决于锁定的频率
Date date = ...;

Lock lock = getLock(date);
lock.lock();