常见的线程池:
ExecutorService executor = Executors.newCachedThreadPool() ;
1、newFixedThreadPool() 创建固定大小的线程池 线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程
2、newCachedThreadPool() 创建一个可缓存的线程池,如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60s不执行任务)的线程,当任务数量增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于系统(JVM)能够创建的最大线程大小
3、newSingleThreadExecutor() 创建一个单线程的线程池。这个线程池只有线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行
4、newScheduledThreadPool() 创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求
5、newSingleThreadScheduledExecutor() 创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求
写一个不太完美的例子:主线程在处理比较慢的业务逻辑时,可用带返回值的submit(Callable)或submit(Runnable, T),也可用不带返回值的submit(Runnable),均可实现异步处理、同步响应(立即跳出主线程,不会造成阻塞延迟)的效果,不过在用带返回值时,必须不在主线程中使用返回值Future的状态(比如其.get()或.isDone()=true方法),否则还是会造成阻塞等待(进而导致前端超时问题,要是跟前端不用交互,则无此问题)。但问题来了,不用异步线程的Future状态(get()或isDone()=true),怎么知道逻辑处理完了呢?这就需要重新开启一个线程去读这个状态值(期间可以把Future对象作为参数传给新线程去监控其isDone()或get()),当然,这个新线程可以是前端请求过来的(如以下的例子),也可以是后端websocket主动请求前端的。还有一种比较好的方案是在主线程中不使用结果值,同样不造成阻塞等待,同样不造成前端请求超时,但在处理逻辑时需要把任务结果Future或业务层面的结果(比如批量场景下的每条数据、或流程场景下的节点状态数据)存到缓存或数据库,同样地前端页面去重新轮训请求获取这些结果已达到得知处理结果的情况。
比较一下子,第一个方案是用后台开启监控线程(用线程池创建线程)去监控结果状态,这个状态值是存储在jvm内存里的,所以要求状态值里边的数据不是太大,且机器一挂掉或停电,会造成这些所有的内存里的数据都会消失,所以要求任务数据的安全度不是太高(比如一些爬虫任务或定时任务啥的,就算挂掉后重新开启任务可以继续跑),但其优点是不用前后端频繁创建链接,且由于是线程池在维护监控线程,不用频繁创建销毁线程,且不存在存库问题,也省去了连接库的那一套消耗。第二个方案的特点是跟上边对立的,安全级别高(因为有状态持久化),但频繁调度时可能会牺牲点时间性能,但jvm的内存压力不会太大。总之,还是老生常谈的“牺牲时间换取空间性能,牺牲空间换取时间性能”问题。
public class ThreadPoolTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService e = Executors.newFixedThreadPool(5);
long l = System.currentTimeMillis();
final Future<Integer> s = e.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("执行长逻辑线程:" + Thread.currentThread().getName());
Thread.sleep(5000);
return 0;
}
});
System.out.println("主线程:" + Thread.currentThread().getName() + "开始任务~结束任务需要毫秒:" + (System.currentTimeMillis() - l));
e.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
long q = System.currentTimeMillis();
while (true) {
if (s.isDone()) {
try {
System.out.println("监控状态线程:" + Thread.currentThread().getName() + ",慢逻辑执行完毕结果:" + s.get());
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (ExecutionException e1) {
e1.printStackTrace();
}
break;
}
}
System.out.println("监控状态线程:" + Thread.currentThread().getName() + ",耗时毫秒数" + (System.currentTimeMillis() - q));
return null;
}
});
}
}