- 之前我们在 *** 作线程的时候都是new Thread,然后使用,然后释放(存在问题就是要加载,释放资源,会浪费资源)。现在不一样了,就我线程池给你new好,准备好,你要使用的时候调用,不用了就释放就好。
- 同样的JDBC数据库连接池:也是之前学习的概念,连接池给你new准备好,然后你要使用的时候调用即可。
- 还有的springIOC容器,也是同样的概念。
常用的ExecutorService接口。
- 我们的Arrays与Collection都有工具类
我们线程池也肯定有工具类ExecutorService executorService = Executors.newFixedThreadPool(5);//一池五个受理
,还有其他的方法
开始中使用的就是ThreadPoolExecutor,如果面试问对线程池的理解,那就是对这个类的理解。如何拿到这个类呢,就要通过旁边没有关系的Executors
- 固定的newFixedThreadPool:它适用于长期任务性能好,创建一个线程池,一池有N个固定的线程,有固定线程数的线程。
同一个线程能多次使用。
`ExecutorService executorService =
Executors.newFixedThreadPool(5);//一池五个受理`
- 一池一个类
感觉有点多此一举,但是它也会有用到的时候。
ExecutorService executorService =
Executors.newSingleThreadExecutor();//单例模式
- 一池可扩容线程
可以扩展的线程池,当你业务多的时候就多new一点
ExecutorService executorService =
Executors.newCachedThreadPool();//一池多线程
3、ThreadPoolExecutor原理
我们上一步使用了三种常见的线程池获得的方法中底层都是使用了ThreadPoolExecutor
- 还使用了阻塞队列
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:
* {@code corePoolSize < 0}
* {@code keepAliveTime < 0}
* {@code maximumPoolSize <= 0}
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue 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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
(1)corePoolSize
- 线程池中的常驻核心线程数,即线程数。
- 其实就是一个线程池里面有多少个线程。
- 线程池中能够通纳同时的最大线程值,此值必须大于一。
- 就是一个业务特别忙的时候,它就会扩容,扩到这个值。
- 多余的空闲线程的存活时间,当前池中线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余线程就会被销毁直到只剩下corePoolSize 个线程为止。
- 相当于线程的生命周期,就是当你之前的业务太忙了,现在闲下来了,就再等keepAliveTime的时间,之后就把这些销毁。
- keepAliveTime的单位。
- 任务队列,被提交但未被执行的任务。
- 这里就是个阻塞队列:其实就可以理解为候客区一样的概念(当前的线程处理不完请求,剩下的请求就会进入候客区)。
- 表示生成线程池中工作线程的线程工厂,用于创建线程,一般默认即可。
- 用于创建线程的
- 拒绝策略,表示当队列满了,并且工作线程大于等于线程池的最大线程池数(maximumPoolSize)时如何来拒绝请求执行的Runnable的策略。
-
如果来请求并且候客区也不满的情况
来了就给你处理,如果没有corePoolSize的线程给你工作,那你就在候客区等。 -
如果继续来人(来了6,7,8)
此时就要扩容了,把你的常驻线程增加到manximumPoolSize。
此时就可以把3,4,5处理了,然后6,7,8进入候客区。 -
假设又有人来了(这次来了10个)
当值窗口和扩容窗口以及候客区都满了,此时就要进行拒绝的Handler来进行处理了。 -
当你1和2,忙完了就走了,然后6和7就去当值窗口进行办理,然后3,4,5都接着办理完成走了,然后此时加班的窗口的keepAlive就要进行计时了,当到了时间后,就要处理销毁了。
-
其实就可以理解如下了
首先提交任务,任何来就要判断核心线程是否有空闲,空闲就接客。如果继续来人,就要在候客区去等。如果继续来人(候客区也满了),就扩容。
-
常用的肯定是:我感觉是使用可扩容的,but阿里巴巴开发手册里面说啦
那为什么不适用JDK自带的呢,其实就是如下的原因,21亿的内存,你直接给干爆了
-
开发的参数如下
前面几个参数都比较简单,那最后一个参数的处理策略就要自己思考了,而且其中的new LinkedBlockingQueue它的我们必须设置大小,不然也很危险
- 看看实现案例
我们自定义的线程池能使用- 继续测试
增加一个就爆炸了 、它的最大值和我们的队列数。
- 继续测试
默认的new ThreadPoolExecutor.AbortPolicy,它直接给报错了。
-
AbortPolicy:阻止系统正常执行
-
CallerRunsPolicy:回退找原来的(之前的谁让你来找我的,你就回退过去找他)
main线程调用了我,回退给main。而且它还有可能是多个都会退给main处理。 -
DiscardPolicy:Discard抛弃,丢弃无法处理的任务
-
DiscardOldestPolicy:抛弃等待最久的那个。
看你的业务是IO密集型,还是CPU密集型。
- 如果是CPU密集型的话,那就CPU加1来设置。
- IO密集型:CPU核数 / 阻塞系数。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)