线程池的使用以及实现原理
一.线程池的使用
1.并发包线程池的体系
java.util.concurrent.Executor : 负责线程的使用与调度的根接口
|–ExecutorService:Executor的子接口,线程池的主要接口
|–ThreadPoolExecutor:ExecutorService的实现类 ,一般就是用这个来创建线程池。阿里的java开发手册有提到不要使用Executor去创建线程池
|–ScheduledExecutorService:ExecutorService的子接口,负责线程的调度
|–ScheduledThreadPoolExecutor:既继承了ThreadPoolExecutor,同时实现了ScheduledExecutorService
2.创建线程池的方式
1.通过Executors ,这种方式很简单,它已经封装好几种线程池给你使用了,但是有一些参数你无法设置,可能会有资源耗尽的风险,主要有四种常见的线程池,如下:
ExecutorService cacheThreadPool = Executors.newCachedThreadPool(); /*优点:很灵活,弹性的线程池线程管理,用多少线程给多大的线程池,不用后及时回收,用则新建。使用SynchronousQueue
缺点:一旦线程无限增长,会导致内存溢出*/
ExecutorService ec = Executors.newFixedThreadPool(0);
/*优点:创建一个固定大小线程池,超出的线程会在队列中等待。使用LinkedBlockingDeque
缺点:不支持自定义拒绝策略,大小固定,难以扩展*/
ExecutorService ss = Executors.newSingleThreadExecutor();
//优点:创建一个单线程的线程池,保证线程的顺序执行,有啥用?使用LinkedBlockingDeque
//缺点:请求处理队列可能会耗费非常大的内存,甚至 OOM ExecutorService sss = Executors.newScheduledThreadPool(1); /* 优点:创建一个固定大小线程池,可以定时或周期性的执行任务。 缺点:任务是单线程方式执行,一旦一个任务失败其他任务也受影响*/
2.通过ThreadPoolExecutor创建,这也是阿里的java开发手册推荐的,其实上面的线程池工具类底层就是通过这个来创建线程池的,具体操作看下面代码:
我们来关注一下里面的参数:
1.线程池的大小:这里面有两个参数,核心线程数和最大总线程数,本来线程池里面一个线程都没有,开始创建的线程就是核心线程,然后,等线程池里面的线程数超过核心线程数之后,会加入阻塞队列,等到这个队列都满了,就创建新的线程去执行任务,等线程数到达最大线程数后,RejectedExecutionHandler来执行拒绝策略。
2.阻塞队列:ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
DelayQueue: 一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue: 一个不存储元素的阻塞队列。
LinkedTransferQueue: 一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque: 一个由链表结构组成的双向阻塞队列。
3.拒绝策略:ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常。 (默认)
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
//用ThreadPoolExecutor创建线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( corePoolSize, //线程池核心池的大小。 maximumPoolSize, //线程池的最大线程数 keepAliveTime, //当线程数大于核心时,此为终止前多余的空闲 //线程等待新任务的最长时间。 unit, //keepAliveTime 的时间单位 workQueue, //用来储存等待执行任务的队列 threadFactory, //线程工厂 handler); //拒绝策略
//这是它的构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)