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一个局部变量,所以您应该这样做。当您必须使用成员字段时,您应该非常努力地使它们不可变。在这种情况下,通过将它们都设置为最终字段,两者ID和都可以是不可变的。n

(2) 为每个任务创建一个新Random对象是 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 回答