java.util.concurrent多线程

时间:2012-08-19 07:02:40

标签: java executorservice future java.util.concurrent callable

我最近开始搞乱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;
}

}

1 个答案:

答案 0 :(得分:0)

  • 在这种情况下我应该使用ArrayList吗?

所有执行程序对此集合执行的操作都是迭代它并将它们添加到自己的队列中。因此,几乎任何集合都应该这样做(如果你有成千上万的任务并使用迭代成本非常高的集合,那么这可能是一个问题,但这种情况非常罕见!)。

  • 这个任务是否有更适合的类,可能更安全。

我认为您选择的课程/方法很好。想不出更适合的课程。实际上没有“更安全线程”的类。东西要么是线程安全的,要么不是。最多有一些类使编码线程安全程序更容易。在这种情况下,我认为你正在采用适当的抽象层次。

  • 任何建设性的批评都会有所帮助。

(1)您应该避免像害虫这样的成员字段,并尽可能使用局部变量。在这种情况下,您可以将result设为局部变量,因此您应该这样做。当你必须使用成员字段时,你应该努力使它们不可变。在这种情况下,IDn都可以通过使它们成为最终字段而不可变。

(2)每个任务创建一个新的Random对象是一个很好的决定IMO。如果您愿意,可以使用此常见优化:

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

如果是Random,您可能无法获得很多收益,但是当涉及昂贵的对象(例如JAXB解析器)时,此优化可能非常有效。