1.什么是线程池?
线程池提供了一种限制和管理资源的方式。每个线程池还维护一些基本的统计信息,例如:已完成的任务数量。
2.使用线程池的好处?
- 1.降低资源消耗:通过重复利用已经创建的线程,降低线程创建和销毁造成的消耗;
- 2.提高响应速度:任务到达时,有时不必等待线程创建,就可以立即执行;
- 3.提高线程的可管理性:线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会降低系统稳定性,使用线程池可以进行统一分配、调优和监控。
3.创建线程池的参数有哪些?
1.corePoolSize(核心线程数):
当提交一个任务到线程池时,如果当前poolSize < corePoolSize时,线程池会创建1个新线程来执行任务,即使有其他空闲的线程能够执行新任务也会创建线程,等到需要执行的任务数量大于核心线程数时就不再创建。如果调用线程池的preStartAllCoreThreads()方法,线程池会提前创建并启动所有基本线程。
2.maximum(线程池最大数量):
线程池允许创建的最大线程数。如果队列满了,并且已经创建的线程数小于最大线程数,则线程池会再创建线程执行任务。注意:如果使用无界队列,那这个参数就没什么效果了。
3.keepAliveTime(线程活动保持时间):
线程池的工作线程空闲后,保持存活的时间。所以,如果任务很多,并且每个任务执行的时间比较短,可以调大时间,提高线程利用率。
4.TimeUnit(线程活动保持时间的单位):
可选的单位有天(DAYS)、?时(HOURS)、分(MINUTES)、毫秒(MILLISECONDS)、微秒(MICROSECONDS,千分之?毫秒)和纳秒(NANOSECONDS,千分之?微秒)。
5.workQueue(任务队列):
用于保持等待执行任务的阻塞队列:
- 1.ArrayBlockingQueue:是?个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进?排序。
- 2.LinkedBlockingQueue:?个基于链表结构的阻塞队列,此队列按 FIFO 排序元素,吞吐量通常要?于ArrayBlockingQueue。静态???法 Executors.newFixedThreadPool() 使?了这个队列。
- 3.SynchronousQueue:?个不存储元素的阻塞队列。每个插?操作必须等到另?个线程调?移除操作,否则插?操作?直处于阻塞状态,吞吐量通常要?于 LinkedBlockingQueue,静态???法
Executors.newCachedThreadPool 使?了这个队列。 - 4.PriorityBlockingQueue:?个具有优先级的?界阻塞队列。
6.threadFactory:
?于设置创建线程的??,可以通过线程??给每个创建出来的线程设置更有意义的名字;
7. RejectExecutionHandler(拒绝策略):4种
队列和线程池都满了,说明线程池处于饱和状态,那么必须采取?种策略处理提交的新任务。这个策略默认是 AbortPolicy,表示?法处理新任务时抛出异常。
4.线程池在2种情况下会拒绝新提交的任务
1.线程池满了,等待队列也满了; 2.调用shutdown等方法关闭线程池后,即便此时可能线程池内依然有没被执行完的任务,但由于线程池已经被关闭了,此时再提交新任务就会被拒绝。
5.线程池的线程数怎么设置?要考虑哪些因素?
1.根据线程执行的任务性质
- CPU密集型,可以设置 等于或略微大于 CPU数量;
- IO密集型,一般是CPU在等IO,可设置为2倍CPU的数量。
2.考虑下游系统的抗并发能力
多线程给下游造成的并发等于你设置的线程数。
- 例如:如果是多线程访问数据库,你就考虑数据库的连接池??设置,数据库并发太多影响其 QPS,会把数据库打挂等问题。
- 如果访问的是下游系统的接?,你就得考虑下游系统是否能抗的住这么多并发量,不能把下游系统打挂了。
3.线程数计算公式:
线程数 = cpu核心数 × 【(线程等待时间+线程cpu时间)/线程cpu时间】= cpu核心数 × (1+平均等待时间/平均工作时间)
6.执行execute()方法和submit()方法的区别
1.execute方法用于提交不需要返回值的任务,所以无法判断任务被线程池的执行成功与否; 2.submit方法用于提交需要返回值的任务。线程池会返回?个Future 类型的对象,通过这个 Future 对象可以判断任务是否执?成功,并且可以通过 Future 的 get() ?法来获取返回值,get() ?法会阻塞当前线程直到任务完成,?使? get(long timeout,TimeUnit unit) ?法则会阻塞当前线程?段时间后?即返回,这时候有可能任务没有执?完。
|