2010-07-06 27 views
0

我有一個有點慢的應用程序。我很抱歉使用線程可能會更快。線程與列表

所以,這裏是我的計劃:我的程序有X型和每個對象X的整數非常大名單的對象列表(讓我們考慮整數爲簡單起見)。

我有一個從X的名單收到對象X一個靜態方法(稱爲getSubsetOfX),並返回對象X返回的列表中的整數列表是包含在X中的所有整數的一個子集

該方法在列表中包含的每個X都被調用。然後我將返回的列表插入到整數列表的列表中。

這是我在一個緊湊的版本解釋代碼:

// Class of object X 
public class X{ 
    public List<Integer> listX; 
    ... 
} 

// Utility class 
public class Util{ 
    // Return a sub-set of Integer contained in X 
    public static List<Integer> getSubsetOfX(X x){...} 
} 


public class exec{ 
    public static void main(String args[]){ 
     // Let's suppose that lx is already filled with data! 
     List<X> lx = new ArrayList<X>(); 

     // List of the subsets of integer 
     List<List<Integer>> li = new ArrayList<ArrayList<Integer>>(); 

     for(X x : lx){ 
      // I want to turn this step "threadrized" 
      li.add(getSubsetOfX(x)); 
     } 
    } 
} 

我不知道如果列表允許併發插入。我不知道如何在其中應用線程。我讀了一些關於線程的內容,但是,由於run()方法不會返回任何內容,因此如何將方法getSubsetOfX(X x)並行?

你能幫我做這個嗎?

回答

3

要說清楚,getSubsetOfX()是需要很長時間的調用,對吧?

對於這類任務,我建議你看看Java的Executor s。第一步是創建一個Callable,其在X的給定實例上運行getSubsetOfX(x)。事情是這樣的:

public class SubsetCallable implements Callable<List<Integer>> { 
    X x; 
    public SubsetCallable(X x) { 
     this.x = x; 
    } 
    public List<Integer> call() { 
     return Util.getSubsetOfX(x); 
    } 
} 

然後你就可以創建一個ExecutorService使用的Executors的方法之一。使用哪種方法取決於您的可用資源和所需的執行模型 - 它們都在文檔中進行了描述。創建ExecutorService後,只需爲您擁有的每個X實例創建一個SubsetCallable,然後將其傳遞給服務即可運行它。我認爲這可能去是這樣的:

ExecutorService exec = ...; 
List<SubsetCallable> callables = new LinkedList<SubsetCallable>(); 
for (X x : lx) { 
    callables.append(new SubsetCallable(x)); 
} 
List<Future<List<Integer>>> futures = exec.invokeAll(lc); 
for (Future<List<Integer>> f : futures) { 
    li.add(f.get()); 
} 

這樣你可以委託激烈計算給其他線程,但你仍然只能訪問一個線程結果列表,所以你不必擔心同步。 (正如winsharp93指出的那樣,ArrayList與大多數Java標準集合一樣,是不同步的,因此對於併發訪問不安全。)

+0

是@David,慢方法是getSubsetOfX(X x)。這個exec.invokeAll()是否運行Callables並行或linnear?謝謝 – marionmaiden 2010-07-06 19:30:02

+0

這取決於你使用哪個'ExecutorService'實現。一般來說,我希望它可以並行地調用它們,直到ExecutorService允許的併發任務數量。例如,如果使用3線程的固定線程池,它應該並行地調用前3個Callables,並且每當它們中的一個完成時,執行它的線程將從列表中獲取下一個Callable。因此,只要有3個或更多任務要運行,總是會有3個任務在任何時間運行。 – 2010-07-06 20:00:46

1

我不知道列表是否允許併發插入。

Class ArrayList

注意,此實現不是 同步。如果多個線程 同時訪問ArrayList實例 ,並且至少一個線程在結構上修改列表 ,則它必須在外部同步 。 (結構上的修改 是指添加或刪除 一個或多個元件,或明確 任何操作調整大小背襯陣列;僅僅 設置元素的值不是 結構修改。)這是 通常通過 同步完成自然封裝列表上的某些對象。如果沒有 這樣的對象存在,該列表應該 「包裝」使用 Collections.synchronizedList方法。 這最好在創建時進行,以防止 意外的不同步 訪問列表:

List list = Collections.synchronizedList(new ArrayList(...)); 

但要注意:同步配有顯著性能成本。這可以通過使用多線程來獲得相關的性能(特別是當計算速度非常快時)。
因此,儘可能避免訪問那些同步集合。首選線程本地列表,然後您可以使用AddAll與您的共享列表合併。

+0

Hi @ winSharp93。你有一些提示可以幫助我在程序中平行進行這一步嗎?問候 – marionmaiden 2010-07-06 19:25:20

+0

嗯 - 這真的取決於你的getSubsetOfX。然而,在很多情況下,使用David Zaslavsky的例子應該沒​​問題。 – Matthias 2010-07-06 19:29:54