2011-08-30 128 views
0

我一直在用Java編程一段時間,但是對於併發編程來說是新的,所以請耐心等待!Java併發集合搜索

我試圖開發出擁有一組集合類[例如的ArrayList]的類,然後找到一個特定值遍歷同時所有集合,停止所有線程如果發現給定值。

我粘貼了下面的代碼,並想知道是否有人知道如何在contains_multiple_collections()中捕獲如果其中一個線程返回Futures返回true?

感謝

格雷厄姆

public class CollectionGroup<V> extends ContainerGroup 
{ 
//... 
    public boolean contains(V value) 
    { 
     boolean containsValue = false; 
     if (mCollections.size() == 1) 
     { 
      containsValue = mCollections.get(0).contains(value); 
     } 
     else 
     { 
      containsValue = contains_multiple_collections(value); 
     } 
     return containsValue; 
    } 

    private boolean contains_multiple_collections(V value) 
    { 
     // thread pool 
     int numberProcessors = mCollections.size(); 
     ExecutorService es = Executors.newFixedThreadPool(numberProcessors); 

     for (int i=0; i<numberProcessors; i++) 
     { 
      AbstractCollection<V> collection = mCollections.get(i); 
      MyCallable callable = new MyCallable(collection,value); 
      Future<Boolean> future = es.submit(callable); 
      //... 
     } 

     return true; 
    } 

    private class MyCallable implements Callable<Boolean> 
    { 
     protected AbstractCollection<V> mCollection; 
     protected V      mValue; 

     public MyCallable(AbstractCollection<V> collection, V value) 
     { 
      mCollection = collection; 
      mValue  = value; 
     } 

     @Override 
     public Boolean call() throws Exception 
     { 
      boolean ok = mCollection.contains(mValue); 
      return ok; 
     } 
    } // class MyCallable 

} // class CollectionGroup 

回答

0

問題是,您的contains_multiple_collections方法不會等待搜索完成。你有兩個我能想到的選擇。第一個涉及一些異步回調實現,其中contains方法不會阻塞,並且可能會將回調/偵聽器對象作爲參數。第二種方法是使包含方法阻塞,直到確定結果。我已經概述了下面後一種方法的示例實現,它沒有經過測試,因此請小心......

/* 
* contains_multiple_collections now blocks until the desired 
* value is located or all searches have completed unsuccessfully... 
*/ 
private boolean contains_multiple_collections(V value) { 
    // thread pool 
    int numberProcessors = mCollections.size(); 
    ExecutorService es = Executors.newFixedThreadPool(numberProcessors); 

    Object lock = new Object(); 
    AtomicBoolean outcome = new AtomicBoolean(false); 
    AtomicInteger remainingSearches = new AtomicInteger(mCollections.size()); 

    for (int i = 0; i < numberProcessors; i++) { 
     AbstractCollection<V> collection = mCollections.get(i); 
     es.submit(new MyRunnable(collection, value, lock, outcome, remainingSearches)); 
    } 

    /* Wait for searches to run. This thread will be notified when all searches 
    * complete without successfully locating the value or as soon as the 
    * desired value is found. 
    */ 
    synchronized (lock) { 
     while (!outcome.get() && remainingSearches.get() > 0) { 
      try { 
       lock.wait(); 
      } catch (InterruptedException ex) { 
       // do something sensible. 
      } 
     } 
     es.shutdownNow(); 
    } 

    return outcome.get(); 
} 

private class MyRunnable implements Runnable { 

    final AbstractCollection<V> mCollection; 
    final V      mValue; 
    final Object    lock; 
    final AtomicBoolean   outcome; 
    final AtomicInteger   remainingSearches; 

    public MyRunnable(AbstractCollection<V> mCollection, V mValue, 
      Object lock, AtomicBoolean outcome, AtomicInteger remainingSearches) { 
     this.mCollection = mCollection; 
     this.mValue = mValue; 
     this.lock = lock; 
     this.outcome = outcome; 
     this.remainingSearches = remainingSearches; 
    } 

    public void run() { 
     boolean ok = mCollection.contains(mValue); 
     if (ok || remainingSearches.decrementAndGet() == 0) { 
      synchronized (lock) { 
       if (ok) { 
        outcome.set(true); 
       } 

       lock.notify(); 
      } 
     } 
    } 
} 
+0

嗨。感謝您的回覆,並花時間概述所需的代碼。我會將你的代碼粘貼到我的手中,讓你知道它的表現。 –

+0

我實現了你的代碼,它效果很好 - 非常感謝你的幫助。另外,我最初提到我是新來的併發編碼,並仔細研究了你的方法。爲了測試實現,我建立了一組4個列表,並用1e7整數填充並隨機插入一個已知值;因此該方法必須通過40mn的值來搜索單個值。它運作良好,速度很快。 –

2

包含,因爲你可能已經發現,在另一個線程的價值將不僅僅停留。做到這一點的唯一方法是循環自己。

對於CPU密集型進程,最佳線程數可能是您擁有的核心數。創建太多的線程會增加開銷,從而降低解決方案的速度。

您還應該記得在完成後關閉()ExecutorService。

如果您想加快搜索速度,我會保留一組所有值,這可能比使用多個線程快10-100倍。

+0

嗨,感謝您的回覆。我的默認構造函數根據處理器的數量創建線程的數量: public CollectionGroup() { super(); int numberProcessors = Runtime.getRuntime()。availableProcessors(); mCollections = new ArrayList >(); mCollections.add(new ArrayList ());對於(int i = } } –

+0

如何使用Set而不是List。在一個線程中設置將比多線程列表更快。 –

+0

嗨。謝謝。我的ContainerGroup是子類CollectionGroup,MapGroup等的層次結構,我爲所有類定義了常見的方法,如contains(),sort()...。因此,包含()將在列表,集合和映射上定義,確認集合將更快。 –

0

你可以反覆遍歷所有的期貨並用get進行輪詢,使用零或幾乎爲零的超時時間,但最好的辦法是給所有的MyCallable提供一個回調,當匹配時應該調用它找到。回調應該取消所有其他任務,可能是關閉ExecutorService

1

您可以使用ExecutorCompletionService。只要保持take()ing(take()阻塞,直到完成的Future就存在),直到找到真正的結果並shutdownNow(),然後找到底層的ExecturService。一旦找到值,這不會立即停止所有線程。

0

我建議使用靜態AtomicBoolean,它是在找到匹配項時設置的。每個線程都可以在繼續之前檢查該值。