面试--线程(二)线程池

线程池类型,创建,核心参数,配置,阻塞队列的不同类型

https://www.jianshu.com/p/210eab345423点击打开链接

http://ifeve.com/java-threadpool/点击打开链接

https://blog.csdn.net/mayongzhan_csdn/article/details/80790966点击打开链接讲的特别好

一什么是线程池?

指  在初始化一个多线程应用程序的过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是创建新的线程。

二:为什么使用线程池

    1:创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率

    2:线程能共享系统资源,如果同时执行的线程过多,就有可能导致系统资源不足而产生阻塞的情况,运用线程池能有效的控制线程最大并发数

    3:对线程进行一些简单的管理,比如:延时执行、定时循环执行的策略等

合理利用线程池能够带来三个好处。第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

 三:创建:

我们可以通过ThreadPoolExecutor来创建一个线程池(常用)。也可以

    ExecutorService executorService= Executors.newCachedThreadPool();(最好不要用)
1new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler)

四:对线程池的配置,就是对ThreadPoolExecutor构造函数的参数的配置

大于coreSize放入阻塞队列BlockQueue 
队列满了在放入池子中直到达到maxSize 
maxSize在放入就使用拒绝策略 

1  -----int corePoolSize => 该线程池中核心线程数最大值

  • corePoolSize(核心线程池,线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程,如果超过corePoolSize,则新建的是非核心线程,核心线程默认情况下会一直存活在线程池中,即使这个核心线程啥也不干(闲置状态)。如果指定ThreadPoolExecutor的allowCoreThreadTimeOut这个属性为true,那么核心线程如果不干活(闲置状态)的话,超过一定时间(时长下面参数决定),就会被销毁掉,很好理解吧,正常情况下你不干活我也养你,因为我总有用到你的时候,但有时候特殊情况(比如我自己都养不起了),那你不干活我就要把你干掉了。

2---int maximumPoolSize  =>  线程池最大大小 , 线程总数最大值           线程总数 = 核心线程数 + 非核心线程数

                                            线程池允许创建最大线程数,它表示在线程池中最多能创建多少个线程;

如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。如果使用了无界的任务队列这个参数就没什么效果。

3---long keepAliveTime  =>非核心线程闲置超时时长

  • keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize。即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

4----TimeUnit(线程活动保持时间的单位):keepAliveTime   可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

5---BlockingQueue<Runnable> workQueue 任务队列:用于保存等待执行的任务的阻塞队列。可以选择以下几个阻塞队列。

  1. ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。可以限定队列的长度,接收到任务的时候,如果没有达到 corePoolSize 的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程 (非核心线程) 执行任务,又如果总线程数到了 maximumPoolSize,并且队列也满了,则发生错误。
  2. LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了 maximumPoolSize 的设定失效,因为总线程数永远不会超过 corePoolSize
  3. SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。这个队列接收到任务的时候,会直接提交给线程处理,而不保留它,如果所有线程都在工作怎么办?那就新建一个线程来处理这个任务!所以为了保证不出现<线程数达到了maximumPoolSize而不能新建线程>的错误,使用这个类型队列的时候,maximumPoolSize 一般指定成 Integer.MAX_VALUE,即无限大
  4. PriorityBlockingQueue:一个具有优先级得无限阻塞队列。
  5. DelayQueue:队列内元素必须实现 Delayed 接口,这就意味着你传进去的任务必须先实现 Delayed 接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务

6---ThreadFactory threadFactory:线程工厂,主要用来创建线程,这是一个接口,new他的时候需要实现他的Thread newThread(Runnable r)方法,

7----RejectedExecutionHandler handler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。

五:ThreadPoolExecutor的策略

通过ThreadPoolExecutor.execute(Runnable command)方法即可向线程池内添加一个任务

当提交一个新任务到线程池时,线程池的处理流程如下:

首先线程池判断基本线程池是否已满?没满,创建一个工作线程来执行任务。满了,则进入下个流程。

其次线程池判断工作队列是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程。

最后线程池判断整个线程池是否已满?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务。

六:常见四种线程池

1:CachedThreadPool()可缓存线程池:无界线程池

  1. 线程数无限制  2有空闲线程则复用空闲线程,若无空闲线程则新建线程.。3一定程序减少频繁创建/销毁线程,减少系统开销

创建方法:ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

2:FixedThreadPool()定长线程池:可控制线程最大并发数(同时执行的线程数);超出的线程会在队列中等待

创建方法:ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads);

3:ScheduledThreadPool()      定长线程池:支持定时及周期性任务执行。

创建方法:ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);

4:SingleThreadExecutor()单线程化的线程池:有且仅有一个工作线程执行任务。所有任务按照指定顺序执行,即遵循队列的入队出队规则

创建方法:ExecutorService singleThreadPool = Executors.newSingleThreadPool();

七:任务拒绝策略  :打开这个链接https://blog.csdn.net/psiitoy/article/details/38587293

1:AbortPolicy:当任务添加到线程池中被拒绝时,它会抛出异常:RejectedExceutionException

2:CallerRunsPolicy:当任务添加到线程池中被拒绝时,它会调用线程池Thread线程对象处理被拒绝的任务。(异步变同步)

3:DiscardOldestPolicy:当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧未处理的任务,然后将被拒绝的任务添加到等待队列中。

4:DiscardPolicy:当任务添加到线程池中被拒绝时,线程池会丢弃被拒绝的任务。

八:线程池的关闭:

平时开发中,大家更多的关注的是线程池的创建、任务的提交和执行。往往会忽略线程池的关闭,甚至忘记调用shutdown()方法,导致内存溢出。大多知道需要调用shutdown()关闭线程池,

线程池提供了两个关闭方法,shutdownNow和shuwdown⽅法。

shutdownNow⽅法的解释是:线程池拒接收新提交的任务,同时⽴刻关闭线程池,线程池里的任务不再执行。

shutdown⽅法的解释是:线程池拒接收新提交的任务,同时等待线程池⾥的任务执行完毕后关闭线程池。

//方法shutdown的作用是使当前未执行完的线 程继续执行,而不添加新的任务。
// shutdown方法不会阻塞,调用shutdown方法后主线程就马上结束了线程池会继续执行完成。

当我们使⽤shutdownNow⽅法关闭线程池时,一定要对任务里进行异常捕获。

当我们使用shuwdown方法关闭线程池时,一定要确保任务里不会有永久阻塞等待的逻辑,否则线程池就关闭不了。

最后,⼀定要记得shutdownNow和shuwdown调用完,线程池并不是⽴刻就关闭了,要想等待线程池关闭,还需调用awaitTermination⽅法来阻塞等待。
线程池自动关闭的两个条件:1、线程池的引用不可达;2、线程池中没有线程;

这里对于条件2解释一下,线程池中没有线程是指线程池中的所有线程都已运行完自动消亡。然而我们常用的FixedThreadPool的核心线程没有超时策略,所以并不会自动关闭。

八:

      1.线程池状态

  2.任务的执行

  3.线程池中的线程初始化

  4.任务缓存队列及排队策略

  5.任务拒绝策略

  6.线程池的关闭

  7.线程池容量的动态调整

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答:Java线程池是Java中的一个重点知识,并且在Java的工作中经常会遇到,因此在面试中也是必问的面试题目。以下是一些常见的Java线程池面试题: 1. 谈谈什么是线程池? 2. 为什么要使用线程池? 3. 你们哪些地方会使用到线程池? 4. 线程池有哪些作用? 5. 线程池的创建方式有哪些? 6. 线程池底层是如何实现复用的? 7. ThreadPoolExecutor核心参数有哪些? 8. 线程池创建的线程会一直在运行状态吗? 9. 为什么阿里巴巴不建议使用Executors? 10. 线程池的底层实现原理是什么? 11. 线程池队列满了,任务会丢失吗? 12. 线程池的拒绝策略类型有哪些? 13. 线程池如何合理配置参数? 这些问题涵盖了线程池的基本概念、使用场景、实现原理以及相关的配置和策略等方面的知识。了解这些问题能够帮助面试者更好地理解和应用Java线程池。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [java线程池面试题有哪些?java线程池常见面试题](https://blog.csdn.net/muli525/article/details/123553744)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [(一)【Java精选面试题】线程池底层实现原理(含答案)](https://blog.csdn.net/qq_30999361/article/details/124924343)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值