newCachedThreadPool的线程池特点:
(1)它是一个可以无限扩大的线程池;它比较适合处理执行时间比较小的任务;corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大;keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。
(2)如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
可以看出该线程池会复用空闲的线程,从而减少创建对象和回收对象带来开销。
项目中用到了newCachedThreadPool,查了一下,为啥用这个:
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractCityAsyncClient.class); private static final int QUEUE_SIZE = 10000; private static final int WORKER_COUNT = 8; private static final ThreadGroup THREAD_GROUP = new ThreadGroup("cityAsyncClientThrceadGroup"); private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool(new ThreadFactory() { private final AtomicInteger threadNumber = new AtomicInteger(1); @Override public Thread newThread(Runnable r) { return new Thread(THREAD_GROUP, r, "cityAsyncClient-thread-pool-" + threadNumber.getAndIncrement()); } }); @Override public void asyncExecRequest(CityRequest cityRequest) { String name = cityRequest.getName(); BlockingQueue<CityRequest> blockingQueue = requestQueueMap.get(name); if (blockingQueue == null) { synchronized (requestQueueMap) { /* double check */ blockingQueue = requestQueueMap.get(name); if (blockingQueue == null) { blockingQueue = new ArrayBlockingQueue<>(QUEUE_SIZE); requestQueueMap.put(name, blockingQueue); for (int i = 0; i < WORKER_COUNT; i++) { EXECUTOR_SERVICE.execute(new Worker(this, blockingQueue)); } } } } try { if (!blockingQueue.offer(cityRequest, 10L, TimeUnit.MILLISECONDS)) { execRequest(cityRequest); } } catch (InterruptedException e) { LOGGER.error("{}.asyncExecRequest error.", this.getClass().getSimpleName(), e); } }
之所以要用到newCachedThreadPool的原因是:
主要是考虑到了(a)如果线程池超过长度,可以灵活回收空闲线程,若无可回收,则新建线程,。因为车辆定位信息可能有时候多,有时候少,考虑到复用性的问题,如果线程闲置的话,可以复用。减少损耗系统资源。
(b )它比较适合处理执行时间比较小的任务;我们的任务到了一定上线就会及时处理。(数量1000,等待时间 5000毫秒,也就是说,不管数据过来多少,只要到了1000条或者5秒就发送)