0

私は最近、java.util.concurrent をいじり始めました。誰かが私のコードの欠陥や悪い習慣を指摘してくれたら幸いです。

プログラムはタイムアウトになるまで実行され、完了したすべてのタスクを出力します。

  • この場合、ArrayList を使用する必要がありますか?
  • おそらくよりスレッドセーフな、このタスクに適したクラスはありますか。
  • 建設的な批判は役に立ちます。

メインクラス

public class ConcurrentPackageTests {

private final ExecutorService executor;

    public ConcurrentPackageTests() {
    executor = Executors.newFixedThreadPool(2);
    this.testCallable(4);
}

private void testCallable(int nInstances) {

    long startTime = System.currentTimeMillis();

    List<Future<Integer>>      futures = null;
    List<Integer>              results = null;
    ArrayList<exCallable>      callables = new ArrayList<exCallable>(nInstances);

    for (int id = 0; id < nInstances; id++) {callables.add(id, new exCallable(id,5));}  

    //get a list of the futures, monitor the futures outcome.
    try { futures = executor.invokeAll(callables, 5, TimeUnit.SECONDS);}
    catch (Exception e) { System.out.println("TIMED OUT");}

    executor.shutdown();    //Stop accepting tasks.

    System.out.println();

    results = getFValues(futures);  //gets all completed tasks
    printOutValues(results, startTime);

}

/**
 * get all integer values that terminated successfully.
 * @param e
 * @return Integer List of results
 */
private List<Integer> getFValues(List<Future<Integer>> e){
    final ArrayList<Integer> list = new ArrayList<Integer>(e.size());
    for (Future<Integer> f : e) {
        if(!f.isCancelled()){
            try {  list.add(f.get(1, TimeUnit.SECONDS));}
            catch (Exception e1) { System.out.println("Err");}      
        }
    }
    list.trimToSize();
    return list;
}

private void printOutValues(List<Integer> results, long startTime){
    for (Integer integer : results) {
        System.out.println("Result: " + integer);
    }   System.out.println("Time: "+ ( System.currentTimeMillis() - startTime ));
}

呼び出し可能

public class exCallable implements Callable<Integer>{

private int n;
int result = 1;
final int ID;

public int getResult() {
    return result;
}

public exCallable(int ID, int pN) {
    this.ID = ID;
    this.n = new Random().nextInt(pN)+ 1;
}

@Override
public Integer call() throws Exception{

    for (int i = 0; i < n; i++) {
        result *= 2;
        Thread.sleep(500);  //Simulate work.
    }

    System.out.println("Computation<" + ID + ">2^"+n+"="+result);
    return result;
}

}
4

1 に答える 1

0
  • この場合、ArrayList を使用する必要がありますか?

エグゼキュータがこのコレクションに対して行うことは、それを反復処理して独自のキューに追加することだけです。したがって、ほとんどすべてのコレクションで実行できます (数千のタスクがあり、反復に非常にコストがかかるコレクションを使用する場合、問題になる可能性がありますが、それは非常にまれな状況です!)。

  • おそらくよりスレッドセーフな、このタスクに適したクラスはありますか。

クラス/メソッドの選択は問題ないと思います。より適したクラスが思い浮かびません。「よりスレッドセーフ」なクラスは実際にはありません。スタッフはスレッドセーフかどうかのどちらかです。せいぜいスレッドセーフなプログラムのコーディングを容易にするクラスしかありません。この場合、適切なレベルの抽象化を行っていると思います。

  • 建設的な批判は役に立ちます。

(1) ペストのようなメンバー フィールドは避け、可能な限りローカル変数を使用する必要があります。この場合、resultローカル変数を作成できるので、そうする必要があります。メンバー フィールドを使用する必要がある場合は、それらを不変にするために非常に努力する必要があります。この場合、両方IDnfinal フィールドにすることで、両方を不変にすることができます。

Random(2)タスクごとに新しいオブジェクトを作成することは、IMO として適切な判断です。必要に応じて、この一般的な最適化を使用できます。

ThreadLocal<Random> rng = new ThreadLocal<Random>(){
    @Override
    protected Random init(){
        return new Random();
    }
}; 
// afterwards...
Random r = rng.get();

Random多くは得られないかもしれませんが、高価なオブジェクト (JAXB パーサーなど) が関係している場合、この最適化は非常に効果的です。

于 2012-08-19T11:00:37.340 に答える