码迷,mamicode.com
首页 > 编程语言 > 详细

[笔记][Java7并发编程实战手册]4.5 运行多个任务并处理第一个结果ThreadPoolExecutor

时间:2015-08-30 21:21:30      阅读:186      评论:0      收藏:0      [点我收藏+]

标签:java   并发编程   多线程   线程池   java 7   

[笔记][Java7并发编程实战手册]系列目录


简介

  看到这个标题的时候,我也很纳闷,因为没有明白所表达的意思。
  ok,并发编程比较常见的一个问题是:当采用多个并发任务来解决一个问题的时候,往往只需要关心这个任务的第一个结果,例如:验证一个算法的时候,假如一个执行5个算法,那么最先返回结果的,就是最快的。

在本章将会学习,如何使用ThreadPoolExecutor来实现类似场景;


本章ThreadPoolExecutor使用心得

  1. 使用 ThreadPoolExecutor.invokeAny(list); 让线程池来帮我们拿到最快返回结果的结果。//执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。一旦正常或异常返回后,则取消尚未完成的任务。如果此操作正在进行时修改了给定的 collection,则此方法的结果是不确定的。
  2. jdk 中说明了:任务成的标识是:未抛出异常,正常返回;
  3. 拿到第一个结果后,执行器会取消未完成的任务,而在多线程中:当线程在活动之前或活动期间处于正在等待、休眠或占用状态且该线程被中断时,抛出InterruptedException异常
  4. 如果所有任务都抛出了异常,那么最终返回结果的时候也会抛出异常。(抛出的异常按照最后返回task)
  5. 还有一个invokeAll方法:当所有任务完成时返回所有任务的future列表。

示例

场景描述:以下程序来模拟在数据库中查找两个用户名(根据用户名和密码),获取最快查询到的用户。

/**
 * Created by zhuqiang on 2015/8/30 0030.
 */
public class Client {
    public static void main(String[] args) {
        ArrayList<Task> list = new ArrayList<Task>();
        list.add(new Task(new UserValidator(),"小强","123456"));
        list.add(new Task(new UserValidator(), "小小强", "123456"));
        list.add(new Task(new UserValidator(), "小小小小强", "123456"));

        ThreadPoolExecutor es = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
        try {
            String s = es.invokeAny(list);//执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。一旦正常或异常返回后,则取消尚未完成的任务。如果此操作正在进行时修改了给定的 collection,则此方法的结果是不确定的。
            System.out.println(s + "   Main——用户验证通过");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        es.shutdown();
    }
}

// 用户验证对象,用来模拟在数据库中查询的过程
class UserValidator{
    public boolean validator(String name,String password){
        long  time = (long)(Math.random() * 10);
        try {
            TimeUnit.SECONDS.sleep(time);
            System.out.println("耗时=========" + Thread.currentThread().getName() + " 耗时:" + time);
        } catch (InterruptedException e) {
            System.out.println("取消=========" +Thread.currentThread().getName()+ " 该任务被中断");
            return false;
        }
//        return new Random().nextBoolean();  //返回一个随机值。表示是否验证通过的标识
        return true;  //始终返回true。用来验证,第一个被找到之后,后面的线程是否会被取消任务
    }
}

class Task implements Callable<String>{
    private UserValidator uv;
    private String name;
    private String password;

    public Task(UserValidator uv, String name, String password) {
        this.uv = uv;
        this.name = name;
        this.password = password;
    }

    @Override
    public String call() throws Exception {
        if (!uv.validator(name,password)){ //没有找到,并抛出一个异常
            System.out.println("没有找到用户========="  + "Task:" + Thread.currentThread().getName()  + "   " + name);
            throw new Exception("没有找到该用户:" + name);
        }
        System.out.println("找到用户========="  + "Task:" + Thread.currentThread().getName()  + "   " + name);
        return name;
    }
}

某一次运行结果:

耗时=========pool-1-thread-2 耗时:1
找到用户=========Task:pool-1-thread-2   小小强
小小强   Main——用户验证通过
取消=========pool-1-thread-2 该任务被中断
没有找到用户=========Task:pool-1-thread-2   小小小小强
取消=========pool-1-thread-1 该任务被中断
没有找到用户=========Task:pool-1-thread-1   小强

结果说明
1. 可以看到,第一个找到之后,结果就被返回了,并且后面未完成的任务被中断了。
2. 此示例的关键点es.invokeAny(list)

查看如果所有任务都没有返回结果呢,就是都抛出了异常
  修改上面的代码,让所有任务都抛出异常,会得到下面的某一次的运行结果:

耗时=========pool-1-thread-1 耗时:3
没有找到用户=========Task:pool-1-thread-1   小强
耗时=========pool-1-thread-1 耗时:0
没有找到用户=========Task:pool-1-thread-1   小小小小强
耗时=========pool-1-thread-2 耗时:6
java.util.concurrent.ExecutionException: java.lang.Exception: 没有找到该用户:小小强
没有找到用户=========Task:pool-1-thread-2   小小强
    at java.util.concurrent.FutureTask.report(FutureTask.java:122)
    at java.util.concurrent.FutureTask.get(FutureTask.java:192)
    at java.util.concurrent.AbstractExecutorService.doInvokeAny(AbstractExecutorService.java:193)
    at java.util.concurrent.AbstractExecutorService.invokeAny(AbstractExecutorService.java:215)
    at java7Concurrency.sync4_4.Client.main(Client.java:18)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.Exception: 没有找到该用户:小小强
    at java7Concurrency.sync4_4.Task.call(Client.java:60)
    at java7Concurrency.sync4_4.Task.call(Client.java:45)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

版权声明:本文为博主原创文章,未经博主允许不得转载。

[笔记][Java7并发编程实战手册]4.5 运行多个任务并处理第一个结果ThreadPoolExecutor

标签:java   并发编程   多线程   线程池   java 7   

原文地址:http://blog.csdn.net/mr_zhuqiang/article/details/48109361

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!