学习使用 ExecutorService.invokeAny(tasks) 方法,我们同时执行多个任务,但我们会在其中任何一个任务完成时做出决定并返回结果。
此方法执行给定的任务列表,返回已成功完成(即未抛出异常)的结果(如果有的话)。
这是一个重载方法。第二种方法采用超时参数,并在给定的超时结束之前返回,无论任务是否完成。
<T> T invokeAny(Collection<? extends Callable<T>> tasks); <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit);
如果我们有各种并发任务可用于解决给定问题,但我们只对第一个结果感兴趣,我们可以使用 invokeAny()
方法。例如,
在这个例子中,我们有两种方法来验证用户的详细信息,即数据库和 LDAP。我们将在不同的任务中同时调用这两种方法。一旦我们能够通过任何给定方法对用户进行身份验证,我们就会断定用户已通过身份验证。
UserValidator 类是模板类,基于源值,它连接到 DB 或 LDAP 并验证用户。
import java.util.concurrent.TimeUnit; public class UserValidator { private final String source; public String getSource() { return source; } public UserValidator(String source) { this.source = source; } public boolean validate(String name, String password) { //Connect to backend based on source value //and validate the credentials try { long duration = (long) (Math.random() * 10); System.out.printf("%s : validating a user in %d seconds\n", this.source, duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { return false; } return true; } }
UserValidatorTask 类代表一个实现Callable 接口的验证任务。这个类的实例可以提交给executor service运行。
import java.util.concurrent.Callable; public class UserValidatorTask implements Callable<String> { private final UserValidator validator; private final String user; private final String password; public UserValidatorTask(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)) { throw new Exception("Error validating user"); } System.out.printf("%s: The user has been found\n", validator.getSource()); return validator.getSource(); } }
最后,Main 类具有创建验证任务的实际逻辑,提交给执行程序服务,然后验证从给定的两个任务中的任何一个获得的第一个结果。
import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Main { public static void main(String[] args) throws InterruptedException { String username = "cundage"; String password = "password"; String result; UserValidator ldapValidator = new UserValidator("LDAP"); UserValidator dbValidator = new UserValidator("DataBase"); UserValidatorTask ldapTask = new UserValidatorTask(ldapValidator, username, password); UserValidatorTask dbTask = new UserValidatorTask(dbValidator, username, password); List<UserValidatorTask> taskList = new ArrayList<>(); taskList.add(ldapTask); taskList.add(dbTask); ExecutorService executor = (ExecutorService) Executors.newCachedThreadPool(); try { result = executor.invokeAny(taskList); System.out.printf("User has been validated from : %s\n", result); //We may cancel all pending //tasks after we have our result executor.shutdown(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
程序输出。
LDAP : validating a user in 6 seconds DataBase : validating a user in 3 seconds DataBase: The user has been found User has been validated from : DataBase
在上面的例子中,我们学会了在执行器服务中执行两个可调用任务。我们学会了使用返回第一个可用结果的 invokeAny()
方法一次性执行所有任务。
我们还看到了 invokeAny()
方法非常有用的用例。
在评论部分把你的问题告诉我。
快乐学习!!
地址:https://www.cundage.com/article/executorservice-invokeany.html