线程池底层原理分析
一、线程池
public ThreadPoolExecutor(int corePoolSize, // 核心线程数int maximumPoolSize, // 最大线程数long keepAliveTime, // 非核心线程存活时间TimeUnit unit, // 非核心线程存活时间单位BlockingQueue<Runnable> workQueue, // 队列ThreadFactory threadFactory,RejectedExecutionHandler handler) {// 拒绝策略if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}
二、线程池底层执行原理
当有一些n个任务需要处理时,此时会判断 n是否大于核心线程数,如果小于核心线程数,则会创建n个线程来处理这n个任务,如果n大于核心线程数,则会把核心线程处理不了的任务放入阻塞队列中进行等待,如果此时阻塞队列满了后,会判断此时任务数是否大于最大线程数,如果n小于最大线程数,则会创建线程来处理核心线程和阻塞队列存不下的任务,即创建那么多的线程,这些线程如果过了存活时间,则会被回收;如果n大于最大线程数,那么那些多出来的任务将不会得到处理,直接进行拒绝策略执行。
三、线程池中执行顺序
提交任务的顺序
- 核心线程区 —> 阻塞队列 —> 非核心线程区
执行任务
- 核心线程区 —> 非核心线程区 —> 阻塞队列
四、线程池创建方式以及各自优缺点
ExecutorService executorService = Executors.newFixedThreadPool(10);public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}
缺点:由于阻塞队列用的是LinkedBlockingQueue,LinkedBlockingQueue的链表长度为int的最大值(2^31-1),
如果任务量特别大时,容易导致OOM(内存溢出)
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}
缺点:由于最大线程数为int的最大值,如果任务量特别大时,会创建大量的线程,占用非常大的cpu资源
