在使用java.util.concurrent下关于线程池一些类的时候,相信很多人和我一样,总是分不清submit()和execute()的区别,今天从源码方面分析总结一下。
通常,我们通过Executors这个工具类提供多种方法来创建适合不同场景的线程池,这里就不一一介绍了。
execute()方法源码如下:
public interface Executor {
void execute(Runnable command);
}
execute()方法的入参为一个Runnable,返回值为void,这时候我们已经知道了execute()方法的来源以及其定义。
接下来,我们来看看,submit()是从哪来的呢?
通过猜测,应该是ExecutorService接口中的,果然,打开源码,看到了submit()方法:
public interface ExecutorService extends Executor {
...
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
...
}
可以看出,在ExecutorService接口中,一共有以上三个sumbit()方法,入参可以为Callable<T>,也可以为Runnable,而且方法有返回值Future<T>;
总结,从上面的源码以及讲解可以总结execute()和submit()方法的区别:
1. 接收的参数不一样;
2. submit()有返回值,而execute()没有;
例如,有个validation的task,希望该task执行完后告诉我它的执行结果,是成功还是失败,然后继续下面的操作。
3. submit()可以进行Exception处理;
例如,如果task里会抛出checked或者unchecked exception,而你又希望外面的调用者能够感知这些exception并做出及时的处理,那么就需要用到submit,通过对Future.get()进行抛出异常的捕获,然后对其进行处理。
execute()方法实际应用实例,在对list数据进行处理,比如需要调用RestFul或webService服务对list其他字段补齐的时候,就用到execute()方法,代码如下:
/**
* 对list字段补齐
* @param list
* @return
*/
public List<VO> findListVO(List<VO> list) {
List<VO> result = Lists.newArrayList();
final int taskSize = 2;
CountDownLatch cdl = new CountDownLatch(taskSize);
//task-1
executor.execute(()->deal1(list,cdl));
//task-2
executor.execute(()->deal2(list,cdl));
return result;
}
/**
* 处理方法1
* @param list
* @param cdl
*/
private void deal1(List<? extends VO> list,CountDownLatch cdl) {
try{
if(list.size()!=0) {
list.forEach(item->{});
}
} finally {
cdl.countDown();
}
}
/**
* 处理方法2
* @param list
* @param cdl
*/
private void deal2(List<? extends VO> list,CountDownLatch cdl) {
try{
if(list.size()!=0) {
list.forEach(item->{});
}
} finally {
cdl.countDown();
}
}
submit()方法在实际应用中的实例,比如一个RestFul接口,只支持一个参数查询,上游系统无法改变传参,这时,为了节省效率,支持多参数查询,我们不得不循环去调用接口,这会导致我们的性能非常慢,为了节省效率,我们不得不把查询放到异步里面去做。代码如下:
/**
* submit()方法
* @param map
* @return
* @throws Exception
*/
public Map<String,Map<String,String>> findMap(Map<String,String> map) throws Exception {
Set<String> set = map.keySet();
Map<String,Map<String,String>> resultMap = Maps.newHashMap();
if(set.size()==1) {
Map<String,String> mapResult = queryMap(set.stream().findFirst().get());
resultMap.put(set.stream().findFirst().get(),mapResult);
} else {
try {
CountDownLatch cdl = new CountDownLatch(set.size());
set.forEach(item->{
es.submit(()-> {
try{
Map<String,String> maps = queryMap(item);
resultMap.put(item,maps);
} finally {
cdl.countDown();
}
});
});
} catch(Exception e) {
throw new Exception();
}
}
return resultMap;
}
/**
* 调用接口的方法
* @param contract
* @return
*/
public static Map<String,String> queryMap(String contract) {
Map<String,String> map = Maps.newHashMap();
return map;
}