平常我们的线程都是继承Thread或者实现Runnable接口,这两种线程的实现方式,都是没有返回值的。
Callable接口和Runable最大的区别是,Callable接口可以取到返回值。
业务场景:
假设有一个业务场景需要取得4个远程接口的数据,并提供到前段展示。很明显如果使用串式的单线程编程,需要按顺序来请求并获取结果,消耗的时间比较长,此时使用Callable,并发请求,将会节省时间。
public class TestCallable implements Callable<String> {
private int id;
public TestCallable(int id) {
this.id = id;
}
@Override
public String call() throws Exception {
int t = new Random().nextInt(10_000);
TimeUnit.MILLISECONDS.sleep(t);
System.out.println("id:" + id + ",本任务执行完成了,耗时: " + t + " 毫秒");
return "id:" + id + ",本任务执行花了 " + t + " 毫秒";
}
}
public static void main(String[] args) {
ExecutorService mExecutor = Executors.newFixedThreadPool(4);
/**
* 需要构建的任务
*/
List<TestCallable> tasks=new ArrayList<>();
tasks.add(new TestCallable(1));
tasks.add(new TestCallable(2));
tasks.add(new TestCallable(3));
tasks.add(new TestCallable(4));
try {
long startTime=System.currentTimeMillis();
List<Future<String>> results=mExecutor.invokeAll(tasks);//调用
System.out.println("=============================");
for(Future<String> f:results){
String result=f.get();
System.out.println(result);
System.out.println(System.currentTimeMillis());
}
System.out.println("=============================");
System.out.println("总耗时: "+(System.currentTimeMillis()-startTime)+" 毫秒");
} catch (Exception e) {
e.printStackTrace();
}
}
分析结果,
上面的代码,使用到ExecutorService 去执行任务,那么假设把newFixedThreadPool设为为1,会有什么效果?
ExecutorService mExecutor = Executors.newFixedThreadPool(1);
修改后,再次执行代码,可以发现,4个任务的执行又变成了串式执行,4个任务的执行时间之和等于总耗时。这说明了Executors.newFixedThreadPool(n)表示了有几只手来执行任务,设定为1,则表示只有1只手来处理池子里的任务,如果设置为4,则表示有4只手处理任务,每只手都可以对应一个任务。
通过上面的日志,我们发现修改这个池子的大小,决定了有几只手执行任务。我们当然是希望这个手越多越好,但是现在的计算机cpu的并发能力如何,cpu的核心数决定了可以有几只手来处理任务。通常推荐的做法时,设置为逻辑核心的倍数,假设cpu时2核4线程,那么设置的线程池应当是4的倍数。
推荐设置为4的n倍
/**
* 固定大小的线程池,此参数很重要,需要是CPU的核心数的倍数,例如CPU的内核核心数是4,n为倍数,则此参数为4n
*/
ExecutorService mExecutor = Executors.newFixedThreadPool(4);
获取cpu的核心数
Runtime.getRuntime().availableProcessors();
则可以设置为
int cpus=Runtime.getRuntime().availableProcessors();
ExecutorService mExecutor = Executors.newFixedThreadPool(cpus);