编写Java Web程序必不可少的会使用线程池,有一些工作还是交给多线程来运行才能更加节省时间,比如访问同时访问两个Http接口,然后对两个Http接口的结果进行处理,这个时候如果仅仅使用单线程来完成这些工作的话会十分的浪费时间因为需要一个一个取数据然后再处理,这个时候就要使用线程池来帮助我们节省时间了。
1、首先要知道为什么使用的是线程池而不是new Thread一下
首先在AlibabaJava开发手册中明确说道使用线程要使用线程池而不是使用new thread的方式来完成,我想在技术上使用new Thread是可以的只不过维护起来不方便也不够优雅,所以我们还是按照行业标准来吧
2、如何使用线程池
如果要使用线程池那么我们就要手动创建线程池,(不要使用Executors来创建线程池),涉及到的类有,ThreadPoolExecutor,FutureTask,接口有Callable,Future,下面一一讲解
2.1 ThreadPoolExecutor
使用ThreadPoolExecutor来创建线程池其中需要几个参数:
corePoolSize 核心线程池大小
maximumPoolSize最大线程池大小
keepAliveTime 线程不工作的时候还能存活多久
TimeUnit 时间的单位
BlockingQueue队列的实现:线程池的大小一定要指定 否则就是一个很大的线程池
- ArrayBlockingQueue 它是一个由数组实现的阻塞队列,FIFO。
- LinkedBlockingQueue 它是一个由链表实现的阻塞队列,FIFO。 吞吐量通常要高于ArrayBlockingQueue。 fixedThreadPool使用的阻塞队列就是它。 它是一个无界队列。
- SynchronousQueue 它是一个没有存储空间的阻塞队列,任务提交给它之后必须要交给一条工作线程处理;如果当前没有空闲的工作线程,则立即创建一条新的工作线程。 cachedThreadPool用的阻塞队列就是它。 它是一个无界队列。
- PriorityBlockingQueue 它是一个优先权阻塞队列。
ThreadFactory创建线程的工厂
RejecedExcutionHandler 饱和策略 当实际线程数达到maximumPoolSize,并且阻塞队列已满时,就会调用饱和策略。
目前由四种饱和策略:
- AbortPolicy 默认。直接抛异常。
- CallerRunsPolicy 只用调用者所在的线程执行任务。
- DiscardOldestPolicy 丢弃任务队列中最久的任务。
- DiscardPolicy 丢弃当前任务。
(面试常问:corePoolSize与maximumPoolSize关系,总的来说默认情况下如果线程的数目小于corePoolSize,那么会通过新增线程来处理新提交的任务而不是复用老的线程,默认情况下corePoolSize中的线程是不过期的需要通过allowCoreThreadTimeOut来设置如果线程池所有线程 都在执行,而且阻塞队列满了 )
创建完线程池,接下来就是提交任务了
线程池提交任务的方法一个是submit 一个是execute,其实本质上submit调用的就是execute 只不过submit会返回一个Future来让用户得到返回的结果,而execute的返回值是一个void。
有两种方法提交任务并且得到返回值:
Future + Callable
public static void main(String[] args) {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
return "sss";
}
};
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 123, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
Future<String> submit = threadPoolExecutor.submit(callable);
submit.get(111,TimeUnit.MILLISECONDS);
}
FutureTask + Callable
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
return "sss";
}
};
FutureTask<String> stringFutureTask = new FutureTask<>(callable);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 123, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
threadPoolExecutor.submit(stringFutureTask);
stringFutureTask.get(111, TimeUnit.MILLISECONDS);
补充一个讲解拒绝策略的好博客:
https://blog.csdn.net/jgteng/article/details/54411423