2010-04-01 52 views
1

我有以下多线程环境的场景 - 请求来到一个方法,我想避免重复处理并发请求。由于多个类似请求可能正在等待在阻塞状态下处理。我使用散列表来跟踪处理的请求,但它会产生内存泄漏,所以应该如何跟踪处理的请求,并避免处理可能处于阻塞状态的相同请求。Java多线程 - 避免重复的请求处理

如何检查任何等待/阻塞的传入请求不是在当前线程中处理的请求。

+0

我不清楚你的意思。你的意思是等同的请求多次出现,但你只想处理这样的请求一次? – 2010-04-01 09:12:36

+0

是的。可以说请求通过一些密钥来区分。一个密钥可能会有多个请求。我只想处理一个。并且其余的等待请求不应该被处理。当我处理一个请求时,新的请求可能会持续,并且会等待,我需要避免所有相同的密钥等待请求。 – seawaves 2010-04-01 09:19:23

回答

1

如果内存泄漏是问题请看WeakHashMap在处理过程中保留你的请求。

另一种解决方案是使用绑定缓存内存...

+0

我想到了这一点,但有没有这样做,而不使用任何数据结构。通过以某种方式构建锁定检查和条件检查 – seawaves 2010-04-01 08:59:19

+0

我们也永远不知道何时会删除weakhashmap的条目,如果在处理所有阻止的请求之前将其删除,则会发生重复的请求处理。 – seawaves 2010-04-01 09:06:53

1

好吧,我想我有点明白你想要什么。

您可以使用ConcurrentSkipListSet作为队列。实现你的排队内容是这样的:

class Element implements Comparable<Element> { 
     //To FIFOnize 
     private static final AtomicLong SEQ = new AtomicLong(); 
     private final long id = SEQ.incrementAndGet(); 

     //Can only be executed once. 
     private final Semaphore execPermission = new Semaphore(1); 


     public int compareTo(Element e){ 
      // If element e1 exists on the queue such that 
      // e.compareTo(e1) == 0, that element will not 
      // be placed on the queue. 
      if(this.equals(e)){ 
       return 0; 
      }else{ 
       //This will enforce FIFO. 
       this.id > e.id ? 1 : (this.id < e.id ? -1 : 0); 
      } 
     } 
     //implement both equals and hashCode 

     public boolean tryAcquire(){ 
      return execPermission.tryAcquire(); 
     } 
} 

现在你的线程应该,

while(!Thread.currentThread().isInterrupted()){ 
    //Iterates from head, therefore simulates FIFO 
    for(Element e : queue){ 
      if(e.tryAcquire()){ 
       execute(e); //synchronous 
       queue.remove(e); 
      } 
    } 
} 

您也可以使用此解决方案的阻断变异(有界的SortedSet,让工作线程阻塞,如果没有元素等)。

1

为什么跟踪HashMap中的请求(或者您可能选择的任何其他方式)会导致内存泄漏,这是没有内在原因的。所有这一切都需要一种方法,一旦它们被处理,就可以移除条目。

这可能意味着让你的请求处理线程:

  • 直接删除该条目;
  • 传回给调度员;或
  • 将请求标记为已处理,因此 表示调度程序可以删除条目。
+0

在什么情况下,我应该清理散列表,我怎么知道没有等待的线程与处理线程有相同的请求。 – seawaves 2010-04-01 13:02:27

+0

@seawaves:当没有等待的线程使用相同的请求时。当调度员得到一个已经有一个线程运行的请求时,你会让这个线程处理它,对吧?所以你的调度器已经有一组请求,一组正在运行的线程和一组等待线程。 *(小写“设置” - 一般数学术语,不是任何特定的数据结构)*。 因此,当您的调度程序发现请求X的运行线程完成时,检查是否有其他线程正在等待在X上工作,并将其移除或启动其中一个服务员。 – CPerkins 2010-04-01 14:58:30