ExecutorService
invokeAny() he invokeAll() 具有阻塞特性
invokeAny
invokeAny 的作用是取得第一个完成任务的结果的值。
如果线程中增加 if (!Thread.currentThread().isInterrupted()) 判断,则会中断这些线程。
其他线程如果抛出 InterruptedException() 异常,且有一个线程可以正常运行时,主线程并不能捕获到。如果希望捕获需要主动增加 try-catch。
如果所有线程全部异常了 将返回最后一个异常并输出。
invokeAny 可以设置超时时间,超时后仍未返回结果,主线程则会捕获到超时异常。
如果只有一个线程 即超时 又 异常了 主线程会捕获到两个异常
public class MyExecutorService {
public static class MyCallableA implements Callable {
@Override
public Object call() throws Exception {
for (int i = 0; i < 10; i++){
System.out.println("CallableA: " + i);
}
System.out.println("CallableA end");
return "CallableA";
}
}
public static class MyCallableB implements Callable {
@Override
public Object call() throws Exception {
for (int i = 0; i < 20; i++){
System.out.println("CallableB: " + i);
}
System.out.println("CallableB end");
return "CallableB";
}
}
public static class MyCallableC implements Callable {
@Override
public Object call() throws Exception {
for (int i = 0; i < 30000; i++){
if (!Thread.currentThread().isInterrupted()) {
System.out.println("CallableC: " + i);
} else {
System.out.println("线程已被中断");
throw new InterruptedException();
}
}
System.out.println("CallableC end");
return "CallableC";
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
List list = new ArrayList<>();
list.add(new MyCallableA());
list.add(new MyCallableB());
ExecutorService executorService = Executors.newCachedThreadPool();
Object o = executorService.invokeAny(list);
System.out.println("result: " + o);
}
}
A线程已经执行结束,但B线程仍在继续执行。
调整main方法
public static void main(String[] args) throws ExecutionException, InterruptedException {
List list = new ArrayList<>();
list.add(new MyCallableA());
list.add(new MyCallableC());
ExecutorService executorService = Executors.newCachedThreadPool();
Object o = executorService.invokeAny(list);
System.out.println("result: " + o);
}
可以看到MyCallableC终止运行
invokeAll
invokeAll用来发挥所有任务的执行结果,在所有任务都返回前将会阻塞线程。
如果有线程执行异常了, 则会讲异常作为返回值返回
和invokeAny异常 都可以设置超时时间 超时后主线程捕获到 Timeout异常
public class MyExecutorService {
public static class MyCallableA implements Callable {
@Override
public Object call() throws Exception {
for (int i = 0; i < 5; i++){
System.out.println("CallableA: " + i);
}
System.out.println("CallableA end");
return "CallableA";
}
}
public static class MyCallableC implements Callable {
@Override
public Object call() throws Exception {
for (int i = 0; i < 5; i++){
if (!Thread.currentThread().isInterrupted()) {
System.out.println("CallableC: " + i);
} else {
System.out.println("线程已被中断");
throw new RuntimeException();
}
}
System.out.println("CallableC end");
return "CallableC";
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
List list = new ArrayList<>();
list.add(new MyCallableC());
list.add(new MyCallableA());
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> result = executorService.invokeAll(list);
for (Future future : result) {
System.out.println("result: " + future.get());
}
System.out.println("main end");
}
}
修改MyCallableC class
public static class MyCallableC implements Callable {
@Override
public Object call() throws Exception {
for (int i = 0; i < 5; i++){
if (!Thread.currentThread().isInterrupted()) {
System.out.println("CallableC: " + i);
} else {
System.out.println("线程已被中断");
throw new RuntimeException();
}
}
if ( 1==1) {
System.out.println("CallableC 异常了");
throw new RuntimeException();
}
System.out.println("CallableC end");
return "CallableC";
}
}
可以看到 主线程阻塞住了 这里需要对。main重的 future 增加 tryCatch
修改main方法 增加 try-catch
public static void main(String[] args) throws ExecutionException, InterruptedException {
List list = new ArrayList<>();
list.add(new MyCallableC());
list.add(new MyCallableA());
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> result = executorService.invokeAll(list);
for (Future future : result) {
try {
System.out.println("result: " + future.get());
}catch (ExecutionException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
}
System.out.println("main end");
}
可以看到其他线程的返回值也获取到了
ExecutorService 中的方法都以便携的方式创建线程池,使用两个主要的方法 invokeAny 获取第一个执行结束的线程的结果 invokeAll 获取所有线程的执行结果