当前位置:首页 > 科技  > 软件

Java为什么不建议使用Executors来创建线程池呢?

来源: 责编: 时间:2024-02-29 14:42:37 123观看
导读我们都知道在面试的过程中,关于线程池的问题,一直都是面试官比较注重的考点,现在也不会有面试官会选择去问创建线程都有哪些方式了,而更多的实惠关注到如何去使用线程池,今天了不起就来和大家说说线程池。Java创建线程池方

我们都知道在面试的过程中,关于线程池的问题,一直都是面试官比较注重的考点,现在也不会有面试官会选择去问创建线程都有哪些方式了,而更多的实惠关注到如何去使用线程池,今天了不起就来和大家说说线程池。lGx28资讯网——每日最新资讯28at.com

Java创建线程池方式

在Java中,创建线程池主要使用java.util.concurrent包下的Executors类。这个类提供了几种静态工厂方法,用于创建和管理不同类型的线程池。以下是一些常见的创建线程池的方式:lGx28资讯网——每日最新资讯28at.com

1.Fixed Thread Pool(固定线程池)

  • 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。
  • 创建方法:Executors.newFixedThreadPool(int nThreads)

2.Cached Thread Pool(缓存线程池)

  • 创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
  • 创建方法:Executors.newCachedThreadPool()

3.Single Thread Executor(单线程执行器)

  • 创建一个使用单个工作线程的 Executor,以无界队列方式来运行该线程。(注意,如果单个线程始终因为等待新任务而处于非活动状态,则在现行线程终止之前,它可能无法终止。)但是,如果线程因为失败而终止,那么会有一个新的线程来替代它。单个线程的优势在于,你无需处理对线程生命周期的管理。
  • 创建方法:Executors.newSingleThreadExecutor()

4.Scheduled Thread Pool(计划线程池)

  • 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
  • 创建方法:Executors.newScheduledThreadPool(int corePoolSize)

5.自定义线程池

除了使用Executors类提供的静态工厂方法创建线程池外,还可以通过实例化ThreadPoolExecutor类来自定义线程池。这种方式提供了更多的灵活性,允许你设置线程池的核心参数,如核心线程数、最大线程数、线程存活时间、任务队列等。lGx28资讯网——每日最新资讯28at.com

示例代码:lGx28资讯网——每日最新资讯28at.com

import java.util.concurrent.*;    public class CustomThreadPool {      public static void main(String[] args) {          int corePoolSize = 5;          int maximumPoolSize = 10;          long keepAliveTime = 60L;          TimeUnit unit = TimeUnit.SECONDS;          BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();          ThreadFactory threadFactory = Executors.defaultThreadFactory();          RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();            ThreadPoolExecutor executor = new ThreadPoolExecutor(                  corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);            // 使用线程池执行任务...      }  }

非自定义线程池的缺点

我们先来看看 Executors 当中的几个方法,也就是上面了不起给大家写的除了自定义线程池的几个方法。lGx28资讯网——每日最新资讯28at.com

public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue<Runnable>());    }

在源码中有一个类,我们明显的看到了队列的身影,那就是 LinkedBlockingQueue。lGx28资讯网——每日最新资讯28at.com

它实现了一个基于链接节点的可选容量的阻塞队列。此队列按 FIFO(先进先出)排序元素。队列的头部是在队列中存在时间最长的元素,队列的尾部是在队列中存在时间最短的元素。新元素总是插入到队列的尾部,而检索操作(如 take 和 poll)总是从队列的头部开始。lGx28资讯网——每日最新资讯28at.com

LinkedBlockingQueue 是一个线程安全的队列,它内部使用了锁和条件变量来保证多线程环境下的正确性和一致性。因为它是阻塞队列,所以它可以用于生产者和消费者模型,在生产者线程和消费者线程之间传递数据。lGx28资讯网——每日最新资讯28at.com

LinkedBlockingQueue 的主要特点就几个lGx28资讯网——每日最新资讯28at.com

  • 容量可选
  • 阻塞操作
  • 非阻塞操作
  • 线程安全
  • 高效的并发性能

为什么说容量可选呢?因为我们如果单独使用这个LinkedBlockingQueue 那么你可以在创建 LinkedBlockingQueue 时指定一个容量,这将限制队列中可以存储的元素数量。如果未指定容量,则队列的容量将是 Integer.MAX_VALUE。当队列满时,任何尝试插入元素的线程都将被阻塞,直到队列中有空间可用。lGx28资讯网——每日最新资讯28at.com

而阻塞操作则是他提供了阻塞的 put 和 take 方法。put 方法用于添加元素到队列中,如果队列已满,则调用线程将被阻塞直到队列有空闲空间。take 方法用于从队列中移除并返回头部元素,如果队列为空,则调用线程将被阻塞直到队列中有元素可用。lGx28资讯网——每日最新资讯28at.com

public void put(E e) throws InterruptedException {        if (e == null) throw new NullPointerException();        // Note: convention in all put/take/etc is to preset local var        // holding count negative to indicate failure unless set.        int c = -1;        Node<E> node = new Node<E>(e);        final ReentrantLock putLock = this.putLock;        final AtomicInteger count = this.count;        ......        public E take() throws InterruptedException {        E x;        int c = -1;        final AtomicInteger count = this.count;        final ReentrantLock takeLock = this.takeLock;        takeLock.lockInterruptibly();        try {            while (count.get() == 0) {                notEmpty.await();            }            x = dequeue();            c = count.getAndDecrement();            if (c > 1).....

我们看一个使用LinkedBlockingQueue的示例:lGx28资讯网——每日最新资讯28at.com

import java.util.concurrent.BlockingQueue;  import java.util.concurrent.LinkedBlockingQueue;    public class ProducerConsumerExample {      public static void main(String[] args) throws InterruptedException {          BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);            Thread producer = new Thread(() -> {              try {                  for (int i = 0; i < 10; i++) {                      System.out.println("Produced: " + i);                      queue.put(i);                      Thread.sleep(200); // 模拟生产耗时                  }              } catch (InterruptedException e) {                  Thread.currentThread().interrupt();              }          });            Thread consumer = new Thread(() -> {              try {                  while (true) {                      Integer item = queue.take();                      System.out.println("Consumed: " + item);                      Thread.sleep(500); // 模拟消费耗时                  }              } catch (InterruptedException e) {                  Thread.currentThread().interrupt();              }          });            producer.start();          consumer.start();            producer.join();          // 注意:这里的 consumer 线程是一个无限循环,所以它不会自然结束。          // 在实际应用中,你需要有一个明确的停止条件来结束消费者线程。      }  }

说到这里感觉说多了,我们回归正题,如果我们使用标准的 newCachedThreadPool 方法,如果线程数设置和任务数不能够配合起来,就比如说设置的线程数是一定的,这个时候,任务数量越多,就会慢慢的进入到队列LinkedBlockingQueue中,队列的话,任务越多,占用的内存越多,最终就非常容易耗尽内存,导致OOM。lGx28资讯网——每日最新资讯28at.com

所以我们不推荐直接使用 Executors 来创建线程池,但是我们更推荐使用 ThreadpoolExecutor创建线程池。原因就是如下的几点:lGx28资讯网——每日最新资讯28at.com

1.资源控制:ThreadPoolExecutor 允许你明确控制并发线程的最大数量,防止因为创建过多的线程而耗尽系统资源。通过合理地设置线程池的大小,可以平衡资源利用率和系统性能。lGx28资讯网——每日最新资讯28at.com

2.线程复用:线程池中的线程可以被多个任务复用,这减少了在创建和销毁线程上花费的时间以及开销,提高了系统的响应速度。lGx28资讯网——每日最新资讯28at.com

3.任务队列:ThreadPoolExecutor 内部维护了一个任务队列,当线程池中的线程都在工作时,新提交的任务会被放在队列中等待执行。这提供了一种缓冲机制,可以平滑处理突发的高并发任务。lGx28资讯网——每日最新资讯28at.com

4.灵活性:ThreadPoolExecutor 提供了多种配置选项,如核心线程数、最大线程数、线程存活时间、任务队列类型等,这些选项可以根据具体的应用场景进行调整,以达到最佳的性能和资源利用率。lGx28资讯网——每日最新资讯28at.com

5.异常处理:当线程池中的线程因为未捕获的异常而终止时,ThreadPoolExecutor 会创建一个新的线程来替代它,从而保持线程池的稳定性。此外,你也可以通过提供自定义的 ThreadFactory 来控制线程的创建过程,例如设置线程的名称、优先级、守护状态等。lGx28资讯网——每日最新资讯28at.com

6.可扩展性:ThreadPoolExecutor 的设计是基于策略的,它使用了多个接口和抽象类来定义线程池的行为,这使得它很容易通过扩展或替换某些组件来适应不同的需求。lGx28资讯网——每日最新资讯28at.com

7.与Java并发库集成:ThreadPoolExecutor 是 Java 并发库 java.util.concurrent 的一部分,这个库提供了丰富的并发工具和类,如锁、信号量、倒计时器、阻塞队列等,这些都可以与 ThreadPoolExecutor 无缝集成,简化多线程编程的复杂性。lGx28资讯网——每日最新资讯28at.com

8.性能监控和调优:ThreadPoolExecutor 提供了一些有用的方法,如 getTaskCount()、getCompletedTaskCount()、getPoolSize() 等,这些方法可以帮助你监控线程池的运行状态,从而进行性能调优。lGx28资讯网——每日最新资讯28at.com

所以你了解了么?lGx28资讯网——每日最新资讯28at.com

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-75332-0.htmlJava为什么不建议使用Executors来创建线程池呢?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 使用ConfuserEx代码混淆工具保护你的.NET应用程序

下一篇: 在Golang中简化日志记录:提升性能和调试效率

标签:
  • 热门焦点
  • K60 Pro官方停产 第三方瞬间涨价

    K60 Pro官方停产 第三方瞬间涨价

    虽然没有官方宣布,但Redmi的一些高管也已经透露了,Redmi K60 Pro已经停产且不会补货,这一切都是为了即将到来的K60 Ultra铺路,属于厂家的正常操作。但有意思的是该机在停产之后
  • 卢伟冰长文解析K60至尊版 对Redmi有着里程碑式的意义

    卢伟冰长文解析K60至尊版 对Redmi有着里程碑式的意义

    在今天的Redmi后性能时代战略发布会结束之后,Redmi总经理卢伟冰又带来了一篇长文,详解了为什么 Redmi 要开启后性能时代?为什么选择和 MediaTek、Pixelworks 深度合作?以及后性
  • 官方承诺:K60至尊版将会首批升级MIUI 15

    官方承诺:K60至尊版将会首批升级MIUI 15

    全新的MIUI 15今天也有了消息,在官宣了K60至尊版将会搭载天玑9200+处理器和独显芯片X7的同时,Redmi给出了官方承诺,K60至尊重大更新首批升级,会首批推送MIUI 15。也就是说虽然
  • SpringBoot中使用Cache提升接口性能详解

    SpringBoot中使用Cache提升接口性能详解

    环境:springboot2.3.12.RELEASE + JSR107 + Ehcache + JPASpring 框架从 3.1 开始,对 Spring 应用程序提供了透明式添加缓存的支持。和事务支持一样,抽象缓存允许一致地使用各
  • JavaScript学习 -AES加密算法

    JavaScript学习 -AES加密算法

    引言在当今数字化时代,前端应用程序扮演着重要角色,用户的敏感数据经常在前端进行加密和解密操作。然而,这样的操作在网络传输和存储中可能会受到恶意攻击的威胁。为了确保数据
  • .NET 程序的 GDI 句柄泄露的再反思

    .NET 程序的 GDI 句柄泄露的再反思

    一、背景1. 讲故事上个月我写过一篇 如何洞察 C# 程序的 GDI 句柄泄露 文章,当时用的是 GDIView + WinDbg 把问题搞定,前者用来定位泄露资源,后者用来定位泄露代码,后面有朋友反
  • 微软邀请 Microsoft 365 商业用户,测试视频编辑器 Clipchamp

    微软邀请 Microsoft 365 商业用户,测试视频编辑器 Clipchamp

    8 月 1 日消息,微软近日宣布即将面向 Microsoft 365 商业用户,开放 Clipchamp 应用,邀请用户通过该应用来编辑视频。微软于 2021 年收购 Clipchamp,随后开始逐步整合到 Microsof
  • 联想小新Pad Pro 12.6将要推出,搭载高通骁龙 870 处理器

    联想小新Pad Pro 12.6将要推出,搭载高通骁龙 870 处理器

    联想小新Pad Pro 12.6将于秋季新品会上推出,官方按照惯例直接在发布会前给出了机型的所有参数。联想小新 Pad Pro 12.6 将搭载高通骁龙 870 处理器,重量为 5
  • 苹果MacBook Pro 2021测试:仍不支持平滑滚动

    苹果MacBook Pro 2021测试:仍不支持平滑滚动

    据10月30日9to5 Mac 消息报道,苹果新的 14 英寸和 16 英寸 MacBook Pro 2021 上市后获得了不错的评价,亮点包括行业领先的性能,令人印象深刻的电池续航,精美丰
Top
Baidu
map