FutureTask是多线程编程中经常用到的一个类,在线程池中,它常常以 executor.submit() 方法调用,它返回了一个Future对象,从而实现了多线程编程中获取异步结果的一种途径。
FutureTask是一个封装了任务的类,可以理解成是Runnable/Callable的包装类。原生的Runnable/Callable都是同步执行,FutureTask像是一个单独的容器,通过持有任务的成员变量,并获取执行该任务的线程,让任务在这FutureTask中运行,然后将运行结果存放在容器中。调用者可以在不同的阶段获取这个结果。
1、线程池创建
public class ThreadPoolUtils {
//可用处理器的Java虚拟机的数量
private static int CORE_SIZE = Runtime.getRuntime().availableProcessors();
private static int CORE_MAX_SIZE = Runtime.getRuntime().availableProcessors()*2;
// volatile 保证线程的存可见性
private static volatile ExecutorService executorService ;
private static ExecutorService getInstance(){
synchronized (ThreadPoolUtils.class){
if(executorService == null){
synchronized (ThreadPoolUtils.class){
return executorService = new ThreadPoolExecutor(CORE_SIZE, CORE_MAX_SIZE , 10, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
}
return executorService;
}
}
public static void submit(Runnable runnable) {
getInstance().submit(runnable);
}
public static <T> Future<T> submitCall(Callable<T> callable) {
return getInstance().submit(callable);
}
public static void synCall(Runnable... runnableSet) {
for (Runnable runnable : runnableSet) {
getInstance().submit(runnable);
}
}
2、查询测试
@RestController
@RequestMapping("/future")
@RequiredArgsConstructor
@Api(value = "FutureTask测试",tags = "FutureTask测试")
@Log4j2
public class ThreadPoolController {
private final ThreadPoolService threadPoolService;
@GetMapping("/search")
@ApiOperation(value = "正常依次查询")
public Result<List<String>> search() throws InterruptedException {
return threadPoolService.searchOrdinary();
}
@GetMapping("/searchConcurrency")
@ApiOperation(value = "FutureTask并发查询")
public Result<List<String>> searchConcurrency() throws InterruptedException, ExecutionException {
return threadPoolService.searchConcurrency();
}
}
public interface ThreadPoolService {
Result<List<String>> searchOrdinary() throws InterruptedException;
Result<List<String>> searchConcurrency() throws InterruptedException, ExecutionException;
}
@Service
@Log4j2
public class ThreadPoolServiceImpl implements ThreadPoolService {
public String select1(String str) throws InterruptedException {
Thread.sleep(1000);
return str;
}
/**正常的依次查询*/
@Override
public Result<List<String>> searchOrdinary() throws InterruptedException {
long l = System.currentTimeMillis();
List<String> list = Lists.newArrayList();
list.add(select1("查询一次"));
list.add(select1("查询二次"));
list.add(select1("查询三次"));
list.add(select1("查询四次"));
log.info("查询耗时:{}",System.currentTimeMillis()-l);
return Result.success(list);
}
/**使用FutureTask并发查询查询*/
@Override
public Result<List<String>> searchConcurrency() throws ExecutionException, InterruptedException {
long l = System.currentTimeMillis();
Future<String> search1 = ThreadPoolUtils.submitCall(() -> select1("查询一次"));
Future<String> search2 = ThreadPoolUtils.submitCall(() -> select1("查询二次"));
Future<String> search3 = ThreadPoolUtils.submitCall(() -> select1("查询三次"));
Future<String> search4 = ThreadPoolUtils.submitCall(() -> select1("查询四次"));
List<String> list = Lists.newArrayList();
list.add(search1.get());
list.add(search2.get());
list.add(search3.get());
list.add(search4.get());
log.info("查询耗时:{}",System.currentTimeMillis()-l);
return Result.success(list);
}
//get 时集中放在后面,以免线程阻塞。
![](https://i-blog.csdnimg.cn/blog_migrate/d8a8d32c8a553b53b2ea3471e247a0ad.png)
正常依次查询:耗时4049
![](https://i-blog.csdnimg.cn/blog_migrate/df735ac5e2c20dff6166c827fb0c0e9c.png)
FutureTask并发查询:耗时 1008
![](https://i-blog.csdnimg.cn/blog_migrate/74d7b99f3659e2b0e5dcd6fe924420e5.png)
FutureTask 并发执行查询可以在复杂查询时提高效率。