2010-04-01 51 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