【问题标题】:java.util.concurrent multi-threadingjava.util.concurrent 多线程
【发布时间】:2012-08-19 07:02:39
【问题描述】:

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

}

【问题讨论】:

  • 我认为没有理由在这里使用ArrayList...另外,听起来您可以使用ExecutorService.invokeAll 来简化很多的逻辑:-)跨度>
  • 谢谢,我没有注意到 ExecutorService.invokeAll。另外,为什么不需要 ArrayList 呢?我可以用什么替换 ArrayList?

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


【解决方案1】:
  • 在这种情况下我应该使用 ArrayList 吗?

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

  • 是否有更适合此任务的类可能更线程安全。

我认为您选择的类/方法很好。想不出更适合的班级。没有真正的“更多线程安全”的类。东西要么是线程安全的,要么不是线程安全的。最多有一些类使编写线程安全程序更容易。在这种情况下,我认为您将使用合适的抽象级别。

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

(1) 您应该避免使用像pestic 这样的成员字段,并尽可能使用局部变量。在这种情况下,您可以将result 设为局部变量,因此您应该这样做。当您必须使用成员字段时,您应该非常努力地使它们不可变。在这种情况下,IDn 都可以通过将它们都设为 final 字段来实现不可变。

(2) 为每个任务创建一个新的 Random 对象是 IMO 的一个不错的决定。如果你喜欢,可以使用这个常见的优化:

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

Random 的情况下,您可能不会获得很多收益,但是当涉及昂贵的对象(例如 JAXB 解析器)时,这种优化可能非常有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多