java并发编程第四章 线程执行器(2)

来源:互联网 发布:数据文员主要做什么的 编辑:程序博客网 时间:2024/05/29 03:49
4.运行多个任务并处理第一个结果
  并发编程中的常见问题就是,当采用多个并发任务解决一个问题时,往往只关心这些任务的第一个结果。这里我们使用ThreadPoolExecutor类实现该场景。
  范例允许用户通过两种验证机制进行验证,但是只要有一种机制验证成功,那么这个用户就验证通过了。
  关键在于ThreadPoolExecutor类的方法invokeAny()方法接收到一个任务列表,然后运行任务,返回第一个完成任务且没有抛出异常的任务执行结果。
  这个方法返回的类型与任务里的call()
  方法返回的类型相同,在这个范例中,将返回String类型的值。
  这里有两个任务可以番红花true值,或者抛出Exception异常。因此有下面四种情况
   1.如果两个任务都返回true值,那么InvokeAny()方法的结果就是首次完成任务的名称。
   2.如果第一个任务返回true值,第二个任务抛出Exception异常,那么invokeAny方法的结果就是第一个任务的名称。
   3.如果第一个任务抛出Exception异常,第二个任务返回true值,那么InvokeAny()方法的结果就是第二个任务的名称。
   4.如果两个任务都抛出异常Exception,那么InvokeAny()方法将抛出ExecutionException异常。
   该方法还有一个其他版本
   invokeAny(Collection<? extends Callable<T>> tasks, long timeout,TimeUnit timeUnit),这个方法执行所有的任务,如果在给定的时间内某个任务已经完成,则返回其结果。

  

实例代码:

1、验证任务类

public class TaskValidator implements Callable<String>{private UserValidator validator;private String user;private String password;public TaskValidator(UserValidator validator, String user, String password) {this.validator = validator;this.user = user;this.password = password;}@Overridepublic String call() throws Exception {if(!validator.validate(user, password)){System.out.printf("%s: The user has not been found\n",validator.getName());throw new Exception("Erro validating user");}System.out.printf("%s The user has been fund\n",validator.getName());return validator.getName();}}

2.用户验证

/** *  * @author fcs * @date 2015-5-5 * 描述:运行多个任务并处理第一个结果 * 说明: */public class UserValidator {private  String name;public UserValidator(String name) {super();this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public boolean validate(String name,String password){Random random = new Random();//模拟处理时间long duration = (long)(Math.random() *10);System.out.printf("Validator %s: validating a user during %d seconds\n",this.name,duration);try {TimeUnit.SECONDS.sleep(duration);} catch (InterruptedException e) {e.printStackTrace();}//返回随机的Boolean值,表示是否通过验证return random.nextBoolean();}}

3.Main 测试类

public class Main {public static void main(String[] args) {String user = "test";String password = "test";UserValidator  user1 = new UserValidator("LDAP");UserValidator  user2 = new UserValidator("DataBase");TaskValidator  task1 = new TaskValidator(user1, user, password);TaskValidator  task2 = new TaskValidator(user2, user, password);List<TaskValidator> task1List = new ArrayList<TaskValidator>();task1List.add(task1);task1List.add(task2);ExecutorService  executor = (ExecutorService)Executors.newCachedThreadPool();String result;try{result = executor.invokeAny(task1List);System.out.printf("Main : Result: %s\n",result);}catch(Exception e){e.printStackTrace();}executor.shutdown();  //终止执行器System.out.println("Main : End of the execution");}}

5.运行多个任务并处理所有结果
     如果想要等待任务的结束,可以使用下面的方法:
     1.如果任务执行结束,那么Future接口的isDone()方法将返回true。
     2.在调用shutdown()方法后,ThreadPoolExecutor类的awaitTermination()方法会将线程休眠,直到所有的任务都执行完毕。
  这两个方法有一些缺点
     1.方法一中仅仅可以控制任务的完成与否。
     2.方法二中必须关闭执行器来等待一个线程,否则调用这个方法的线程将立即返回。
     ThreadPoolExecutor类还提供了一个方法,允许发送一个任务列表给执行器,并等待列表中所有任务执行完成。该方法就是InvokeAll(),返回一个List的Future对象。
     关于InvokeAll()方法的重要地方,就是使用Future对象仅用来获取任务的结果。
     当所有的任务执行结束时这个方法也执行结束了,如果在返回的Future对象上调用isDone()方法,那么所有的调用将返回true值。
     另一个版本的方法:
     InvokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit timeUnit)当所有的任务都执行完毕,或者超时的时候(无论哪个首先发生),
     这个方法将返回
     保持任务状态和结果的Future列表。

  实例代码:

  1.存储实例中并发任务产生的结果

/** *  * @author fcs * @date 2015-5-5 * 描述:运行多个任务并处理所有结果 * 说明: */public class Result {<span style="white-space:pre"></span>private String name;<span style="white-space:pre"></span>private int value;<span style="white-space:pre"></span>public String getName() {<span style="white-space:pre"></span>return name;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>public void setName(String name) {<span style="white-space:pre"></span>this.name = name;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>public int getValue() {<span style="white-space:pre"></span>return value;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>public void setValue(int value) {<span style="white-space:pre"></span>this.value = value;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}
2.Task类

public class Task implements Callable<Result> {private String name;public Task(String name) {this.name = name;}@Overridepublic Result call() throws Exception {System.out.printf("%s: Starting\n",this.name);long duration = (long)(Math.random() * 10);System.out.printf("%s: waiting %d seconds for results\n",this.name,duration);TimeUnit.SECONDS.sleep(duration);int value = 0;for(int i =0 ;i< 5;i++){value+=(int)(Math.random() * 100);}Result result = new Result();result.setName(this.name);result.setValue(value);return result;}}

3.Main测试类

public class Main {public static void main(String[] args) {ExecutorService executor = (ExecutorService)Executors.newCachedThreadPool();List<Task> taskList = new ArrayList<Task>();for(int i =0 ;i < 3;i++){Task task = new Task(i+"");taskList.add(task);}List<Future<Result>> resultList = null;try {//该方法返回上一步创建的Future类型的列表resultList = executor.invokeAll(taskList);} catch (InterruptedException e) {e.printStackTrace();}executor.shutdown();System.out.println("Main: Printing the results");for(int i =0;i< resultList.size();i++){Future<Result> future = resultList.get(i);try {Result result = future.get();System.out.println(result.getName()+" : "+result.getValue());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}}}





0 0
原创粉丝点击