1.使用线程池时,生产环境中线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式的原因:
使用Executors创建线程池有三种方式:
1.newCachedThreadPool():创建缓存线程池。
当一个任务提交时,corePoolSize为0不创建核心线程,SynchronousQueue是一个不存储元素的队列,可以理解为队里永远是满的,因此最终会创建非核心线程来执行任务。
对于非核心线程空闲60s时将被回收。因为Integer.MAX_VALUE非常大,可以认为是可以无限创建线程的,在资源有限的情况下容易引起OOM异常
源码为:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
2.newSingleThreadExecutor():创建单线程的线程池。
当一个任务提交时,首先会创建一个核心线程来执行任务,如果超过核心线程的数量,将会放入队列中,因为LinkedBlockingQueue是长度为Integer.MAX_VALUE的队列,可以认为是无界队列,因此往队列中可以插入无限多的任务,
在资源有限的时候容易引起OOM异常,同时因为无界队列,maximumPoolSize和keepAliveTime参数将无效,压根就不会创建非核心线程
源码为:
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
3.newFixedThreadPool():创建指定线程数的线程池。
FixedThreadPool是固定核心线程的线程池,固定核心线程数由用户传入,同样是因为LinkedBlockingQueue是长度为Integer.MAX_VALUE的队列,可以认为是无界队列,容易引起OOM异常
源码为:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
以上三种方式都是执行:new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime, TimeUnit.MILLISECONDS,runnableTaskQueue);五个参数分别为:核心线程数,最大线程数,存活前最大空闲时间(针对非核心线程),时间单位,任务队列(等待执行任务的队列)
执行逻辑:
1.判断核心线程数是否已满,未满则创建线程执行任务 2.若核心线程池已满,判断队列是否满,若未满则加入队列中 3.若队列已满,判断线程池是否已满,若未满创建线程执行任务 4.若线程池已满,则采用拒绝策略处理无法执执行的任务
因此:建议开发者自己使用new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime, TimeUnit.MILLISECONDS,runnableTaskQueue, threadFactory,handler);来创建线程池,这样可以根据硬件的不同来设置相对应的参数。
2.DCL(Double check Lock)双检查锁,先检查缓存中对象是否存在,不存在则加锁,然后再判断缓存中对象是否存在,存在则直接返回,不存在则从数据库中查询,然后保存到缓存中