并发编程中一个常见的问题是: 有不同的并发任务解决一个问题时, 只需要那些任务的第一个结果. 例如想排序一个数组, 有不同的排序算法. 您可启动各种算法并获得第一个排好序的结果, 也就是对于一个给定的数组的最快的排序算法.
本节的示例代码在 com.elanzone.books.noteeg.chpt4.sect05 package中
用户校验类 : UserValidator
public boolean validate(String name, String password) { Random random = new Random(); try { long duration = (long) (Math.random() * 10); System.out.printf("Validator %s: Validating a user during %d seconds\n", this.name, duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { return false; } return random.nextBoolean(); }
校验任务类 : TaskValidator
@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("Error validating user"); } System.out.printf("%s: The user has been found\n", validator.getName()); return validator.getName(); }
控制类 : Main
String username = "test"; String password = "test"; UserValidator ldapValidator = new UserValidator("LDAP"); UserValidator dbValidator = new UserValidator("DataBase"); TaskValidator ldapTask = new TaskValidator(ldapValidator, username, password); TaskValidator dbTask = new TaskValidator(dbValidator, username, password);
List<TaskValidator> taskList = new ArrayList<>(); taskList.add(ldapTask); taskList.add(dbTask);
ExecutorService executor = (ExecutorService) Executors.newCachedThreadPool();
String result; try { result = executor.invokeAny(taskList); System.out.printf("Main: Result: %s\n", result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }
executor.shutdown(); System.out.printf("Main: End of the Execution\n");
本例的关键在Main类中。 ThreadPoolExecutor 类的 invokeAny() 方法接受一个任务列表,启动它们并返回第一个没有抛出异常正常结束的任务的结果. 此方法返回的数据类型和启动的任务的 call() 方法返回的数据类型一致。本例中返回String。
本例有 2 个返回随机 boolean 值的 UserValidator 对象。每个 UserValidator 对象被用于一个 Callable(TaskValidator类)对象。 如果 UserValidator 类的 validate() 方法返回 false, TaskValidator 类抛出异常;否则它返回 true.
这样我们有2个可能返回 true 或 抛出一个 Exception 异常的任务,有以下 4 种可能性: