talk is cheap, show me the code 直接上代码
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* @created on 2018 07 28 22:17
*/
public class ThreadPoolProduction {
public static void main(String[] args) {
BussinessService bussinessService = new BussinessServiceImpl();
//新建一个线程池,池中有两个线程,注意这里使用的是fiexd 注意和cached的区别
ExecutorService executorService = Executors.newFixedThreadPool(2);
//注意这里使用的是callable 而不是runable。
ArrayList<Callable<Integer>> tasks = new ArrayList<>();
for (int i = 0; i < 10; i++) {
tasks.add(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
bussinessService.handleBussiness();
return 0;
}
});
}
try {
//由于我们使用的是callable,所以在执行完成后,会拿到反馈信息,而runable不可以
List<Future<Integer>> futures = executorService.invokeAll(tasks);
for (Future<Integer> future : futures) {
System.out.println(future.get());
}
} catch (ExecutionException e) {
//这里生产环境不可以这么写,不要生吞(swallow)异常,处理的方式有很多种,比如可以向日志系统追加日志
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
首先,新建了一个线程池,注意这个线程池是fixed的(线程池创建主要由四种方式,具体哪四种,我还真不记得了,阿里的面试问到了, 印象非常深的记住了两种,就是fixed和cached,当时回答了这两个的区别,并且讲了下fixed的缺点,后面我们会深入讲解这个。)
其次,我们新建了一个任务的列表tasks(注意这个列表的泛型是callable)
最后,我们提交批量执行这个任务,由于线程池中只有两个线程,所以会看见每次都是打印出两行。(执行这里是最关键的,因为之前我们的任务都是基于callable的,所以执行之后会返回一个future,future大家都熟悉了,项目中也有使用到,使用的场景就是处理完成之后会返回一个回执内容。)
项目中要看具体的业务场景了,由于报表项目是使用mysql来使用数据库的资源进行计算的,根据生产环境的服务器和rds mysql数据的连接资源,所以最适合不过使用fixed的线程池了,报表,计算数据的时候,出错了就出错了,大不了重新算,所以现在的生产环境中,拿到callable执行后的结果也并没有做任何的处理。这里就有人会问了,如果真的出错了怎么办,又没有拿到错误的信息,都不会知道是不是出现了错误,实际上如果报表在计算任务中出现了失败,那么会在具体的业务代码中,记录失败的日志信息到es,显示在kibana中。当然,实际上,就算是没有记录错误信息,出现了错误没被发现,也不会有太大的问题。很多时候,恰巧不解决,反而降低了实现的复杂度,因为在报表的业务实现上,做了一些设计,哪怕是出错了,也没关系的。至于这些设计是哪些,后面我会找时间整理出来。
下图是程序运行过程中,线程的使用情况,可以看到pool-1 线程池中有2 similar threads, 分别是pool-1-thread-2 pool-1-thread-1两个线程当前没有要处理的任务,处于等待状态
/**
* @created on 2018 07 28 22:51
*/
public interface BussinessService {
void handleBussiness();
}
/**
* @created on 2018 07 28 22:52
*/
public class BussinessServiceImpl implements BussinessService {
@Override
public void handleBussiness() {
System.out.println("处理业务逻辑");
// 为了观察线程是根据线程池设置的线程数,批量执行的,这里加上线程休眠
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}