/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
*/
V get() throws InterruptedException, ExecutionException;
以上为源码,以下详细描述。
一、问题由来
LinkedBlockingQueue
:一个基于链表实现的阻塞队列,按 FIFO 排序任务,可以设置容量(有界队列),不设置容量则默认使用Integer.Max_VALUE
作为容量(无界队列)。- AbortPolicy拒绝策略:任务阻塞队列满了会直接抛出RejectedExecutionException异常。
public class TestThreadPool {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2
, 5
, 5
, TimeUnit.SECONDS
, new LinkedBlockingQueue<>(2)
, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r);
}
}, new ThreadPoolExecutor.AbortPolicy());
//用有返回值的summit方法,测试拒绝策略
for (int i = 0; i < 100; i++) {
int a = i;
Future<Object> future = threadPool.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
System.out.println(Thread.currentThread().getName()+".....循环次数为"+a);
return Thread.currentThread().getName();
}
});
Object result = future.get();
System.out.println(result);
}
}
}
起初,通过summit方法来测试拒绝策略AbortPolicy,然而运行以上程序后并没有看到有异常抛出。输出结果如下:
由上面执行结果可知, 并没有看到预期的结果,只有2个线程在执行结果。而corePoolSize为2,maximumPoolSize为5,可是并没有看到5个线程;使用的指定长度为2的任务阻塞队列LinkedBlockingQueue,队列满了,应该抛出异常才对。网上查资料是这样说的:
二、验证get()的阻塞效果
将上面的代码最后两行注释掉,如下图,运行结果如下:
// Object result = future.get();
// System.out.println(result);
这次出现了预期的效果,看到工作线程共5个(0~4),循环次数共7次(0~6) ,其中有2次在有界阻塞队列中等待,因为拒绝策略使用的是直接抛异常的方式AbortPolicy。
也说明Future的get()方法获取结果是阻塞的,即当前线程执行结束并获取到结果后才会继续执行下个线程,这样就无法实现多线程的效果。所以,能不获取时,尽可能不获取。
三、测试有无get的结果差多少
上面的代码做几处改动:
- 任务阻塞队列的限定长度去掉,即变为无界阻塞队列;
- 循环体中sout语句注释掉;循环次数改为100万次;
- 增加打印耗时的代码;
import java.util.concurrent.*;
public class TestThreadPool {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2
, 5
, 5
, TimeUnit.SECONDS
, new LinkedBlockingQueue<>()
, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r);
}
}, new ThreadPoolExecutor.AbortPolicy());
//用有返回值的summit方法,测试拒绝策略
long start = System.currentTimeMillis();
for (int i = 0; i < 1_000_000; i++) {
int a = i;
Future<Object> future = threadPool.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
// System.out.println(Thread.currentThread().getName()+".....循环次数为"+a);
return Thread.currentThread().getName();
}
});
Object result = future.get();
// System.out.println(result);
}
long end = System.currentTimeMillis();
System.out.println(end-start);
}
}
当有 Object result = future.get(); 这一行时,输出结果为耗时:10509ms;
当没有 Object result = future.get(); 这一行时,输出结果为耗时:144ms;
可见,结果还是很明显的。