线程池可以通过Executors快捷的创建。
创建可缓存的线程池,线程数可以无限多。
ExecutorService service1 = Executors.newCachedThreadPool();
创建定长的线程池。
ExecutorService service2 = Executors.newFixedThreadPool(10);
创建定长的线程池,可定时周期执行。
ExecutorService service3 = Executors.newScheduledThreadPool(10);
创建单一线程的线程池。
ExecutorService service4 = Executors.newSingleThreadExecutor();
为了便于理解,看下内部创建的方式:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); } public static ExecutorService newFixedThreadPool(int paramInt) { return new ThreadPoolExecutor(paramInt, paramInt, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }
创建线程池参数:
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, // coreSize,核心线程数 2, // MaxSize,最大线程数 60, // 60,线程空闲的时间,超过时间,则会被销毁 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3) // 指定一种队列,存放任务待处理。 // (有界队列) // new LinkedBlockingQueue<Runnable>() , new MyRejected()// 拒绝策略 );
pool中添加任务数为1,因为核心线程为1,会被立即执行。
pool中添加任务数为2/3/4,因为核心线程为1,会被放到队列中等待执行。
pool中添加任务数为5,因为核心线程为1,队列为3,此时核心线程正在执行,且队列已经满了,但是max为2,所以会启动一个新的线程执行任务5。(此时如果1还没有执行完,那么5会优先2/3/4执行)。
pool中添加任务数为6,因为核心线程为1,队列为3,此时核心线程正在执行,且队列已经满了,且max为2,此时任务6不知道既没线程去执行,又没有队列存储,只能走拒绝策略。
整体的顺序,添加任务时首先看核心线程还有没有,有就立即执行,没有就放到队列中等待,当队列满了,就看max-core线程数还有没有空间,如果有就立即启动线程执行,没有就走拒绝策略。
当队列采用LinkedBlockingQueue这种无界队列时,max就没有用了,因为超过core的任务会放到队列中等待执行。
所以可以看到newCachedThreadPool的创建方式:
core为0,max为Integer最大值,空闲存活时间为60s,队列为没有空间的SynchronousQueue,此时可以知道,这个队列是没用的,任务全部会执行。
再看下newFixedThreadPool的创建方式:
core和max都为我们设置的固定大小的线程数,队列是无界队列,即最大可以同时运行我们设置的任务数。
newScheduledThreadPool的创建方式,可定时执行的原因是因为队列使用的是DelayedWorkQueue(对DelayQueue的优化):
newSingleThreadExecutor的创建方式,单一线程: