Callable是可以有返回结果的,但是我们必须要等到所有的Callable执行完成,即我们需要阻塞住主线程。
但Callable是如果实现阻塞的呢?下面几个例子说明阻塞的方法,一共四种方式执行Callable线程列表
- 使用线程池的submit方法但不调用get方法(不可行)
- 线程池依次submit线程并依次调用get方法(不可行)
- 线程池submit十个线程,并将返回的future加入一个列表,循环调用列表中future的get方法
- 线程池的invokeAll方法调用线程List
第一种,使用线程池的submit方法但不调用get方法
首先:线程池submit但不调用get方法。可以看到没有按照顺序来,即没有阻塞主线程
//定义一个线程安全的int,用于线程中++
static AtomicInteger integer = new AtomicInteger(0);
public static void main(String[] args) {
//定义一个线程数为10的线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.HOURS, new ArrayBlockingQueue(10));
//定义一个Callable类
class TestCallable implements Callable<Integer>{
@Override
public Integer call(){
try{
//睡3秒
Thread.sleep(3000);
}catch (Exception e){
System.out.println("出现异常");
}
System.out.println("结果为:"+integer.incrementAndGet());
return 0;
}
}
//通过线程池submit十个TestCallable,但不调用get方法
for(int i = 0; i < 10; i++){
Future<Integer> f = executor.submit(new TestCallable());
}
//写在子线程之后的主线程的操作
System.out.println("三十多岁");
//关闭线程池
executor.shutdown();
}
打印结果如下:
三十多岁
结果为:1
结果为:5
结果为:6
结果为:4
结果为:3
结果为:2
结果为:7
结果为:10
结果为:8
结果为:9
Process finished with exit code 0
第二种,线程池依次submit线程并依次调用get方法
然后,线程池依次submit线程并依次调用get方法。运行时发现,是3秒钟打印一次,共打印30秒,完全是串行的,而不是并行的十个线程同时进行。看打印结果,也是有序的1到10,而不是无序的,但我们知道线程池并行执行线程时应该是无序的。
//定义一个线程安全的int,用于线程中++
static AtomicInteger integer = new AtomicInteger(0);
public static void main(String[] args) {
//定义一个线程数为10的线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.HOURS, new ArrayBlockingQueue(10));
//定义一个Callable类
class TestCallable implements Callable<Integer>{
@Override
public Integer call(){
try{
//睡3秒
Thread.sleep(3000);
}catch (Exception e){
System.out.println("出现异常");
}
System.out.println("结果为:"+integer.incrementAndGet());
return 0;
}
}
//通过线程池submit十个TestCallable,并调用get方法
for(int i = 0; i < 10; i++){
Future<Integer> f = executor.submit(new TestCallable());
//调用future的get方法
try {
f.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//写在子线程之后的主线程的操作
System.out.println("三十多岁");
//关闭线程池
executor.shutdown();
}
结果如下:
结果为:1
结果为:2
结果为:3
结果为:4
结果为:5
结果为:6
结果为:7
结果为:8
结果为:9
结果为:10
三十多岁
Process finished with exit code 0
第三种、线程池submit十个线程,并将返回的future加入一个列表,循环调用列表中future的get方法
再然后,通过线程池submit十个线程,并将返回的future加入一个列表,循环调用列表中future的get方法。可以看到输出结果达到了我们想要的效果,并行执行了10个线程,而且阻塞了主线程:
//定义一个线程安全的int,用于线程中++
static AtomicInteger integer = new AtomicInteger(0);
public static void main(String[] args) {
//定义一个线程数为10的线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.HOURS, new ArrayBlockingQueue(10));
//定义一个Callable类
class TestCallable implements Callable<Integer>{
@Override
public Integer call(){
try{
//睡3秒
Thread.sleep(3000);
}catch (Exception e){
System.out.println("出现异常");
}
System.out.println("结果为:"+integer.incrementAndGet());
return 0;
}
}
//通过线程池submit十个TestCallable,并加入future的列表
List<Future<Integer>> list = new ArrayList<>();
for(int i = 0; i < 10; i++){
Future<Integer> f = executor.submit(new TestCallable());
//加入list
list.add(f);
}
//循环调用future列表的get方法
for(int i = 0; i < 10; i++){
try {
list.get(i).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//写在子线程之后的主线程的操作
System.out.println("三十多岁");
//关闭线程池
executor.shutdown();
}
打印结果如下:
结果为:5
结果为:4
结果为:3
结果为:2
结果为:1
结果为:6
结果为:9
结果为:10
结果为:8
结果为:7
三十多岁
Process finished with exit code 0
第四种、线程池的invokeAll方法调用线程List
invokeAll调用线程List,可以看到也达到了我们想要的效果,但没用Future的get方法,所以invokeAll不用Future的get方法也会阻塞主线程线程:
//定义一个线程安全的int,用于线程中++
static AtomicInteger integer = new AtomicInteger(0);
public static void main(String[] args) {
//定义一个线程数为10的线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.HOURS, new ArrayBlockingQueue(10));
//定义一个Callable类
class TestCallable implements Callable<Integer>{
@Override
public Integer call(){
try{
//睡3秒
Thread.sleep(3000);
}catch (Exception e){
System.out.println("出现异常");
}
System.out.println("结果为:"+integer.incrementAndGet());
return 0;
}
}
//定义十个TestCallable,加入list
List<Callable<Integer>> list = new ArrayList<>();
for(int i = 0; i < 10; i++){
list.add(new TestCallable());
}
//通过invokeAll唤醒所有线程,没有get方法也是会阻塞主线程的
try {
executor.invokeAll(list);
} catch (InterruptedException e) {
e.printStackTrace();
}
//写在子线程之后的主线程操作
System.out.println("三十多岁");
executor.shutdown();
}
打印结果为:
结果为:4
结果为:1
结果为:3
结果为:2
结果为:5
结果为:7
结果为:6
结果为:8
结果为:9
结果为:10
三十多岁
Process finished with exit code 0