Java 中的线程池是什么 (面试必背)?

1,944 total views, 12 views today

这个文章不会涉及太深的线程知识(太深我也不懂)。这里只是把线程池的一些概念整理一下,当被问到这个题目的时候,尽可能背给面试官听就行了。

不要问为什么,因为 JVM 就是这么设计的,要问为什么,除了设计者本人,我觉得没人能回答的更好。

为什么要有线程池

任何需要大量创建的资源,都可以通过池化技术来缓解性能问题。线程池也是这种思想,提前创建好一批线程,使用的时候直接获取线程,而不需要临时创建,销毁,提高性能。连接池,常量池也是同一种思想。使用线程池的好处有以下几点,1. 避免重复创建和销毁线程,节省资源,提高性能。2,加强对线程的管理,避免无限制的创建线程,使用线程池,可以对线程统一分配,监控。

 

Java 自带的线程池

在 JDK1.5 之后,Java 自带了线程池,所以不需要自己去实现。创建线程池的核心方法就是 ThreadPoolExecutor 类的构造函数。

下面的代码就是 JVM 中的源码,看看注释就行了。

该代码注释详细的描述了构造方法的参数意义,使用的时候可查 API 文档。但是面试的时候,需要背诵记忆的。

 

  • corePoolSize:核心池的大小。默认的,创建了线程池后,线程池中的线程数为 0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到 corePoolSize 后,继续提交的任务被保存到阻塞队列中,等待被执行;如果执行了线程池的 prestartAllCoreThreads() 方法,线程池会提前创建并启动所有核心线程。
  • maximumPoolSize:线程池最大线程数。这个参数通常是大于等于 corePoolSize,当线程数大于 corePoolSize 后,还有任务提交过来,则会被放入阻塞队列,当阻塞队列也满了之后,仍然有新任务提交过来,那么就会继续创建新线程,直到当前线程数大于 maximumPoolSize 后,则不再创建。(如果此时还有任务提交过来,那么就会采取拒绝策略)
  • keepAliveTime:闲置线程的存活时间,即当线程没有任务执行时,继续存活的时间;默认情况下,该参数只在线程数大于 corePoolSize 时才有用;
  • unit:参数 keepAliveTime 的时间单位
  • workQueue:一个阻塞队列,用来存储等待执行的任务。
    1、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按 FIFO 排序任务;
    2、LinkedBlockingQuene:基于链表结构的阻塞队列,按 FIFO 排序任务,吞吐量通常要高于 ArrayBlockingQuene;
    3、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于 LinkedBlockingQuene;
    4、priorityBlockingQuene:具有优先级的无界阻塞队列;
  • threadFactory:ThreadFactory 是一个接口,通过线程工厂可以对线程的一些属性进行定制。
  • handler:RejectedExecutionHandler 是一个接口,它定义了拒如何拒绝创建新线程,即当线程数满的时候,还有新任务提交时的拒绝策略。默认的,提供了 4 种处理策略:
  1. ThreadPoolExecutor.AbortPolicy   默认的,抛出异常 RejectedExecutionException;
  2. ThreadPoolExecutor.CallerRunsPolicy 这个策略重试添加当前的任务。
  3. ThreadPoolExecutor.DiscardPolicy  忽略任务,没有异常信息;
  4. ThreadPoolExecutor.DiscardOldestPolicy 先将阻塞队列中第一个任务抛弃,把当前任务再加到队列。

通过线程工厂可以对线程的一些属性进行定制。

通过 ThreadPoolExecutor 类的构造方法创建线程池比较繁琐,Java 通过 Executors 提供 4 个静态方法,预设值了几种线程池。分别为:

  • newCachedThreadPool —— 线程数是无限大。keepAliveTime 为 60 秒,线程空闲置 60 秒就会被回收,它采用 SynchronousQueue 为阻塞队列,SynchronousQueue 的没有存储空间,意味着阻塞队列总是满的,所以当请求来的时候,如果没有闲置的线程,那么就新建一个线程。一般不太推荐使用,理论上,它可以榨干操作系统的线程资源。
  • newFixedThreadPool ——corePoolSize 和 maximunPoolSize 是相同的,所以它是一个线程池固定的线程池,可控制线程最大并发数。keepAliveTime 为 0,一旦有闲置线程,则立即回收掉。它采用 LinkedBlockingQueue 为阻塞队列,是一个无界队列,所以只要有任务来,都能排队进来,不会被拒绝。通常推荐使用这种线程池。
  • newScheduledThreadPool—— 创建一个定长线程池,支持定时及周期性任务的执行。它采用 DelayQueue 为阻塞队列,其中的任务只有到期时才能从队列中取出。
  • newSingleThreadExecutor—— 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序 (FIFO, LIFO, 优先级) 执行。几乎不会用到这种线程池。

 

上述就是背诵要点。具体实践的话,还是亲自写代码跑为好。

原创文章,转载请注明出处!http://www.javathings.top/java中的线程池是什么?/

About: wusq


发表评论

邮箱地址不会被公开。 必填项已用*标注