Java并发:在任务池中查找任务失败

时间:2013-06-12 18:49:56

标签: java multithreading concurrency

以下SSCCE显示从服务器获取记录(比如说)。 ExecutorService用于创建2个线程的ThreadPool,我调用了所有这些线程的Timeout为3秒。 故意我做了一些失败的任务。

现在我的问题是,如何让EmpID的任务失败?

MainClass:

public class MultiThreadEx {
    public static void main(String[] args) {

        String[] empIDArray = {
                "100", "200", "300", "400", "500", 
                "600", "700", "800", "900", "1000", 
                "1100", "1200", "1300", "1400", "1500"
            };

        List<ThreadTaskEach> taskList = new ArrayList<ThreadTaskEach>();
        try {
            for(String empID : empIDArray) {
                taskList.add(new ThreadTaskEach(empID));
            }
        } catch(Exception e) {
            System.out.println("Exception occured: " + e.getMessage());
        }

        List<Future<Map<String, String>>> futureList = null;
        try {
            ExecutorService service = Executors.newFixedThreadPool(2);
            futureList = service.invokeAll(taskList, 3, TimeUnit.SECONDS);
            service.shutdown();
        } catch(InterruptedException ie) {
            System.out.println("Exception occured: " + ie.getMessage());
        }

        for(Future<Map<String, String>> future : futureList) {
            try {
                Map<String, String> resultMap = future.get();

                for(String key : resultMap.keySet()) {
                    System.out.println(resultMap.get(key));
                }

            } catch(ExecutionException ee) {
                System.out.println("Exception occured: " + ee.getMessage());
            } catch (InterruptedException ie) {
                System.out.println("Exception occured: " + ie.getMessage());
            } catch(CancellationException e) {
                System.out.println("Exception occured: " + e.getMessage());
            }
        }

    }
}

线程类

class ThreadTaskEach implements Callable<Map<String, String>>{

    private String empID;

    public ThreadTaskEach(String empID) {
        this.empID = empID;
    }

    @Override
    public Map<String, String> call() throws Exception {
        try {
            return prepareMap(empID);
        } catch(Exception e) {
            System.out.println("Exception occured: " + e.getMessage());
            throw new Exception("Exception occured: " + e.getMessage());
        }
    }

    private Map<String, String> prepareMap(String empID) throws InterruptedException {
        Map<String, String> map = new HashMap<String, String>();

        if(Integer.parseInt(empID) % 500 == 0) {
            Thread.sleep(5000);
        }

        map.put(empID, empID + ": " + Thread.currentThread().getId());

        return map;
    }
}

在上面的代码500中,1000 ..无法在3秒内完成。

Map<String, String> resultMap = future.get();

所以,当我为这些任务说future.get()时,我得到了CancellationException。但是如何从任务中获得EmpID?

1 个答案:

答案 0 :(得分:6)

您可以逐个invokeAll每个任务,而不是使用submit,并将每个未来存储在地图中:

Future<?> f = executor.submit(task);
map.put(f, task.getId());

现在当你试图获得时,如果你有异常,你可以使用地图返回到id。但是,您需要在每个future.get()上设置超时,这可能对您的用例不实用。

另一种方法是使用invokeAll which guarantees to return the futures in the same order as the tasks that were submitted的规范。

  

返回表示任务的Futures列表,按照与给定任务列表的迭代器生成的顺序相同的顺序

只要您使用List,迭代顺序就固定了,您可以匹配两个列表:

    for (int i = 0; i < futureList.size(); i++) {
        Future<Map<String, String>> future = futureList.get(i)
        try {
            Map<String, String> resultMap = future.get();

            for(String key : resultMap.keySet()) {
                System.out.println(resultMap.get(key));
            }
        } catch(ExecutionException ee) {
            System.out.println("Exception in task " + taskList.get(i).getId());
        }
    }

请确保使用具有稳定迭代顺序的集合(ArrayList很好)。