方法invokeAny,invokeAll具有阻塞性。
- invokeAny取得第一个方法的返回值,当第一个任务结束后,会调用interrupt方法中断其它任务。
- invokeAll等线程任务执行完毕后,取得全部任务的结果值。
invokeAny
invokeAny(Collection<? extends Callable<T>> tasks):
public class InvokeAnyTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
List<Callable<String>> list = new ArrayList<>();
list.add(new MycallableA());
list.add(new MycallableB());
try {
String value = executorService.invokeAny(list);
System.out.println("最后结果值是======:" + value);
} catch (Exception e) {
System.out.println("++++++++++++main方法中捕获异常+++++++++++++++");
e.printStackTrace();
}
executorService.shutdown();
}
static class MycallableA implements Callable<String> {
@Override
public String call() throws Exception {
for (int j = 0; j < ThreadLocalRandom.current().nextInt(99); j++) {
Math.random();
Math.random();
Math.random();
Math.random();
}
System.out.println(Thread.currentThread().getName() + " ===A==== ");
return "A";
}
}
static class MycallableB implements Callable<String> {
@Override
public String call() throws Exception {
for (int j = 0; j < ThreadLocalRandom.current().nextInt(99999999); j++) {
Math.random();
Math.random();
Math.random();
Math.random();
}
System.out.println(Thread.currentThread().getName() + " ====B=== ");
`
return "B";
}
}
}
从运行结果可以看出:invokeAny取得了 “A” 的值,但是B还在继续运行,直到运行结束。
执行任务中发生异常
- 如果在上述代码的MycallableA或者MycallableB任意一个发生了异常,但抛出的异常没有在main中捕获,控制台也不会打印任何异常信息。 只能call()中 try catch 显示捕获。
- 如果都发生异常,返回最后一个异常并且输出,在ExecutionException中捕获。
public class InvokeAnyTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
List<Callable<String>> list = new ArrayList<>();
list.add(new MycallableA());
list.add(new MycallableB());
try {
String value = executorService.invokeAny(list);
System.out.println("最后结果值是======:" + value);
} catch (InterruptedException e) {
System.out.println("++++++++++++InterruptedException 方法中捕获异常+++++++++++++++");
e.printStackTrace();
} catch (ExecutionException e) {
System.out.println("++++++++++++ExecutionException 方法中捕获异常+++++++++++++++");
e.printStackTrace();
}
executorService.shutdown();
}
static class MycallableA implements Callable<String> {
@Override
public String call() throws Exception {
for (int j = 0; j < ThreadLocalRandom.current().nextInt(99); j++) {
Math.random();
Math.random();
Math.random();
Math.random();
}
throw new Exception("MycallableA异常------");
}
}
static class MycallableB implements Callable<String> {
@Override
public String call() throws Exception {
for (int j = 0; j < ThreadLocalRandom.current().nextInt(99999999); j++) {
Math.random();
Math.random();
Math.random();
Math.random();
}
throw new Exception("Myca
llableB异常------");
}
}
}
输出结果:
超时invokeAny
在指定时间内取得第一个先执行完任务的结果值,如果超时,抛出TimeoutException,并且interrupt线程。
invokeAll
返回所有任务的结果。
- 当线程池中线程发送发生异常时,直接在抛出,在mian方法中捕获
public class InvokeAnyTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
List<Callable<String>> list = new ArrayList<>();
list.add(new MycallableA());
list.add(new MycallableB());
try {
List<Future<String>> futures = executorService.invokeAll(list);
for (Future<String> future : futures) {
System.out.println(future.get());
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
System.out.println("===Main异常==");
}
executorService.shutdown();
}
static class MycallableA implements Callable<String> {
@Override
public String call() throws Exception {
for (int j = 0; j < ThreadLocalRandom.current().nextInt(9); j++) {
Math.random();
Math.random();
Math.random();
Math.random();
}
return "a";
}
}
static class MycallableB implements Callable<String> {
@Override
public String call() throws Exception {
for (int j = 0; j < ThreadLocalRandom.current().nextInt(99999999); j++) {
Math.random();
Math.random();
Math.random();
Math.random();
}
throw new Exception("B");
// return "b";
}
}
}
输出结果:
分析: A没有异常,先返回A的结果,B在运行过程中发生异常,在mian方法ExecutionException中捕获异常。只要future.get()才会需要捕获ExecutionException异常,如果不调用此方法,线程发送异常,是不会被捕获到。
超时invokeAll
invokeAll 方法超时后,interrupt线程,但不会抛出runTimeException异常,在Future对象调用get()方法时,才会CancellationException异常。假设有5个线程,2个线程未超时,这时get()会得到这两个线程返回的结果。