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

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;
	}

	@Override
	public 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;
	}

	@Override
	public 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();
			}
		}
	}
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值