介绍:
创建多个线程并且进行管理的容器(可以创建和管理线程,并且给线程分配任务)
为什么使用线程池
若程序中有许多短时间任务的线程任务,那么就需要很多次的创建和销毁线程,很明显会增大开销,并且在一个新的线程创建了,另一个线程任务还未结束,那么占据的资源势必会越来越多,很容易造成死锁等问题
而线程池中的任务结束后,并不会死亡,一直等待下一个任务的到来
优点:
- 重用已经存在的线程,减少线程的创建和销毁的开销
- 可以有效控制最大并发的线程数,提高了系统资源的使用率避免很多竞争,如OOM、死锁等
- 可以提供定时和定期的执行方式,单线程,并发数量控制等功能
线程池可以使得对线程得管理更加方便,并且对高并发的控制尽在掌握
实现方式:
-
创建ThreadPoolExecutor对象
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize:线程的核心线程数
maximumPoolSize:最大线程数
keepAliveTime:线程总数大于核心线程数时,终止多余空闲线程的时间
unit:keepAliveTime参数的单位
workQueue:等待队列,若线程池活动的线程达到了核心线程数,将新任务放入该队列
threadFactory:定制线程的创建过程
handler:拒绝策略,当workQueue满了,拒绝新来线程的方式
-
newFixedThreadPool方式——Executors工厂创建方式
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }
可以看出,newFixedThreadPool也是通过ThreadPoolExecutor方式创建,可以指定线程数和线程创建过程
这是一种线程数量固定的创建方式
-
newSingleThreadExecutor方式——Executors工厂创建方式
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); }
只有一个线程的线程池,常用于线程顺序执行,并且任意时间只能有一个任务被执行
-
newCachedThreadPool方式——Executors工厂创建方式
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }
CachedThreadPool使用SynchronizedQueue作为阻塞队列,SynchronizedQueue是不存储元素的阻塞队列,实现“一对一的交付”,也就是说,每次向队列中put一个任务必须等有线程来take这个任务,否则就会一直阻塞该任务,如果一个线程要take一个任务就要一直阻塞知道有任务被put进阻塞队列。
因为CachedThreadPool的maximumPoolSize为Integer.MUX_VALUE,因此CachedThreadPool是无界的线程池,也就是说可以一直不断的创建线程。corePoolSize为0 ,因此在CachedThreadPool中直接通过阻塞队列来进行任务的提交。
线程池的状态
RUNNING:能接受新的任务,也能处理阻塞队列中的任务
SHUTDOWN:不能接受新提交的任务,但是可以继续处理阻塞队列队列中的任务
STOP:不能接受新任务,也不能处理队列中的任务
TIDYING:若所有任务都终止了,并且有效线程数为0,线程池会调用terminated方法进入TERMINATED状态
TERMINATED:神马也没做
拒绝策略
AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
DiscardPolicy:丢弃任务,但是不抛出异常
DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务
CallerRunsPolicy:由调用线程处理该任务