Java 多线程优化:使用 ThreadPoolExecutor 提高性能

前言

在多线程编程中,线程池是一个非常常见的概念。Java 提供了默认的线程池实现,可以通过 Executors 工厂类创建线程池,但是使用过程中可能出现资源浪费和性能瓶颈等问题。本文介绍 Java 多线程优化中的一种经典解决方案:使用 ThreadPoolExecutor 线程池实现,以提高性能和优化代码结构。

ThreadPoolExecutor 简介

ThreadPoolExecutor 是 Java 线程池的核心实现类,实现了 ExecutorService 接口,支持异步执行长时间计算或 I/O 操作的任务。它将任务提交到一个线程池中,然后由池中的线程执行任务。ThreadPoolExecutor 的构造方法如下:

------ ---------------------- ------------- --- ---------------- ---- -------------- -------- ----- ----------------------- ---------- ------------- -------------- ------------------------ --------

其中参数含义如下:

  • corePoolSize :核心线程数量;
  • maximumPoolSize :最大线程数量,包括核心线程和非核心线程;
  • keepAliveTime :非核心线程的存活时间,单位为 timeunit;
  • unit :存活时间的时间单位;
  • workQueue :任务队列;
  • threadFactory :线程工厂,用于创建线程;
  • handler :拒绝策略,当任务队列已满且线程池中的线程数达到最大线程数量时,如何拒绝请求执行的任务。

ThreadPoolExecutor 优化方案

在 ThreadPoolExecutor 的实现中,主要优化点为:核心线程数的设置、线程池的队列类型、队列长度及拒绝策略等。下面分别进行详细介绍。

设置核心线程数

核心线程数是指始终存在的工作线程数,即使所有的核心线程都处于忙碌状态,也不会关闭它们。使用 ThreadPoolExecutor 时,可以适当设置核心线程数,尽可能地利用 CPU 资源。通常建议设置为 CPU 核心数 + 1,保证 CPU 能够得到最大利用。

线程池队列

线程池的队列类型也是一个非常重要的优化点。线程池的队列主要有三种,分别是 SynchronousQueue、LinkedBlockingQueue 和 ArrayBlockingQueue。

其中 SynchronousQueue 是一种无界队列,队列空间为 0,不会存储任务。SynchronousQueue 可以在线程池中支持较小的线程数量时,实现最优的吞吐量。但是当线程数增加到一定数量时,SynchronousQueue 的高吞吐量优势就会被限制,导致线程不断创建和销毁,不利于CPU的使用。

LinkedBlockingQueue 是一种无界队列,内部使用链表实现。在缺乏资源时,LinkedBlockingQueue 会继续执行任务,而线程数量增加到了 maximumPoolSize 之后,再新加任务时就会使用拒绝策略,防止队列溢出。

ArrayBlockingQueue 是一种有边界的队列,内部使用数组实现。设置队列长度后,只有在队列未满时才能向其中加入新的任务,否则就会使用拒绝策略。

队列长度

Bob Nystrom 在《Java threads as a service》一文中提到,队列长度的设置与机器配置、机器负载和具体场景有关。过大的队列长度可能导致过多的内存使用,而过小的队列长度可能在短时间内导致队列溢出,从而影响线程池的正常工作。因此,我们需要在实际使用过程中进行频繁的调整。

拒绝策略

线程池的拒绝策略对于后续执行的任务产生直接的影响。当线程池的队列已满时,拒绝策略可以避免大量的线程等待或降低线程堆栈的深度。

ThreadPoolExecutor 提供四种拒绝策略:AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy 和 DiscardPolicy。

  • AbortPolicy:默认的拒绝策略,会直接抛出 RejectedExecutionException 异常,防止服务器资源耗尽。
  • CallerRunsPolicy:直接在主线程中执行任务,即将任务提交给 mainThread 执行。
  • DiscardOldestPolicy:丢弃由主线程提交的任务,然后将当前任务提交到队列尾部。
  • DiscardPolicy:直接丢弃任务,不提供处理。

示例代码

下面是针对前面提到的多线程优化方案的示例代码:

--
 - ----------
 --
------------------ -------- - --- --------------------- --- ---- ----------------- --- ------------------------- --- ------------------------------------------------------------- --- ----------------------------------


--
 - -------
 --
------------------ ----------- - --- ---------------------------- -------- --- ----------------- --- ------------------------ --- ------------------------------------------------------------ --- ---------------------------------------

--
 - ------- ---------- ------
 --
------------------ ------ - --- --------------- -- -
    ------ ------------------- --------------
    ---- --------- --------------
    ------ -------------
---
---------------------------
-----------------
-- ------------------------------------- ------------------- -
    -----------------------------
-

总结

在 Java 多线程编程中,正确合理地使用 ThreadPoolExecutor 是非常关键的。在实现过程中,合理设置核心线程数、队列类型以及队列长度和拒绝策略等,可以让代码实现更为稳定和高效。总之,针对具体的使用场景和代码实现,合理配置 ThreadPoolExecutor 对代码架构的设计和性能的提升具有至关重要的作用。

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/64a267bd48841e9894ec3d50


猜你喜欢

  • Node.js 中的 Unit Test 测试框架:使用方法和技巧

    在前端开发中,测试是非常重要的一环。而 Unit Test 是测试中的一种非常重要的方式。在 Node.js 中,我们有很多可以使用的 Unit Test 测试框架,比如 Tape、Mocha、Jas...

    1 年前
  • AngularJS 中处理单页应用程序中的页面刷新的最佳方法

    随着单页应用程序变得越来越流行,如何处理页面刷新成为了作为前端工程师必须面对的一个问题。在 AngularJS 中,我们可以使用以下几种方法来处理单页应用程序中的页面刷新。

    1 年前
  • Vue-cli3 改版使用 webpack4 搭建简单脚手架

    前言 随着 Vue.js 的广泛应用,Vue 脚手架也愈发成为前端开发的必需工具。在这个过程中,Vue-cli 系列一直是最受欢迎的选择之一。而在 2018 年初, Vue-cli3 横空出世,一经推...

    1 年前
  • ES7 新特性之 Proxy.revocable() 方法

    在 ES2016 中,引入了 Proxy 对象作为一种新的控制对象上的访问和修改的方式。Proxy 可以用于构建元编程 API,使其更加灵活和可扩展。而在 ES7 中,新增了 Proxy.revoca...

    1 年前
  • 解决 React 中的 TypeScript 类型错误问题

    在使用 React 进行前端开发中,往往会使用 TypeScript 作为开发语言。不过,当在实际开发中遇到 TypeScript 类型错误问题时,很多开发者会感到困惑和疑惑。

    1 年前
  • ES10 中的数组排序方法优化

    在前端开发中,对数组排序的需求经常会出现。在 ES10 中,对数组排序方法进行了优化,使得排序更加方便和高效。本篇文章将详细介绍 ES10 中的数组排序方法的使用和优势,并提供示例代码,帮助读者更好地...

    1 年前
  • 使用 Azure Functions 和 Event Grid 建立轻量 Serverless 应用

    前言 Serverless 架构是一种新型的云计算架构,它抛弃了传统的服务器架构,大大降低了运维成本,能够更快的构建和发布应用程序。在 Serverless 架构中,应用程序代码在云端运行,而具体的计...

    1 年前
  • Material Design 中设计背景颜色的指南

    在 Material Design 设计中,背景颜色的选择非常重要,它可以影响用户对应用程序的整体感觉和易用性。本文将介绍 Material Design 中设计背景颜色的指南,包括颜色的选取、如何搭...

    1 年前
  • Hapi.js 实战:使用 joi-number-extensions 进行数字校验

    在前端开发中,对用户输入的数据进行校验是至关重要的一环。Hapi.js 是一个流行的 Node.js Web 框架,它提供了强大的路由功能和验证机制,可以快速构建安全可靠的 Web 应用。

    1 年前
  • Angular 中如何实现高性能的数据绑定?

    Angular 是一款流行的前端框架,相较于其他框架,Angular 有着比较好的性能表现。其中,数据绑定是 Angular 最重要的特性之一,也是开发者最常使用的功能之一。

    1 年前
  • RESTful API 中的文件上传和下载处理

    在 Web 开发中,处理文件上传和下载是一项广泛应用的任务。RESTful API 中的文件上传和下载处理尤其需要注意,因为这涉及到如何将文件发送到服务器以保存到文件系统并如何从服务器响应下载请求。

    1 年前
  • 解决 ESLint 在 TypeScript 项目中无法校验路径映射的问题

    在 TypeScript 项目中,我们经常会使用路径映射来简化模块的导入,比如使用 @ 来代替 src 目录。但是在使用 ESLint 进行代码检查时,可能会出现无法识别路径映射的问题,这会导致 ES...

    1 年前
  • 基于 Custom Elements 实现 toast 提示框的技巧及优化

    前言 在前端开发中,我们常常需要使用到提示框。提示框可以起到提醒用户、提示操作结果等作用,是一个非常常用的组件。本文将介绍如何基于 Custom Elements 实现一个简单的 toast 提示框,...

    1 年前
  • 如何在 LESS 中优雅的处理 z-index

    在前端开发过程中,z-index 是一个非常重要的概念,它控制着元素在页面上的层次关系。然而,随着页面越来越复杂,z-index 的管理也越来越复杂和困难。为了解决这个问题,我们可以使用 LESS 来...

    1 年前
  • CSS Reset 中清除 IE 默认内边距 / 外边距的理解和实现

    什么是 CSS Reset ? CSS Reset(CSS 重置)是一种技术,可以通过重置(或覆盖)浏览器的默认样式,来达到统一不同浏览器之间的表现,从而减少跨浏览器布局问题。

    1 年前
  • 如何解决 Cypress 测试时遇到的 502 错误

    问题描述 在使用 Cypress 进行 Web 应用程序测试时,偶尔会遇到 502 错误的情况。这种错误通常是由服务器或代理服务器发送给客户端的,表示服务器或代理服务器无法连接到要访问的网站的服务器。

    1 年前
  • 解决 Flexbox 布局下的 gap 问题

    在使用 Flexbox 布局进行内容排版时,我们经常会使用 gap 属性来控制子元素之间的间距。然而,目前并没有标准化的 gap 属性可供使用,而不同浏览器的处理也不尽相同,这时我们就需要使用一些技巧...

    1 年前
  • 解决使用 ES12 中的 Logical Assignment Operators 与 Logical Operators 的错误问题

    在最新版的 ECMAScript 2021 中,增加了一种新的语法,即 Logical Assignment Operators 和 Logical Operators。

    1 年前
  • RxJS 和 Observable - 那些操作符雷区

    随着前端开发的发展,越来越多的应用程序需要实现异步数据流的操作,而 RxJS 正是这个时候应运而生。它是一款强大的 JavaScript 库,采用了一种响应式编程的思想,可以帮助开发者更加便捷和高效地...

    1 年前
  • 使用 Mocha 测试 Node.js 中的 child_process 模块

    前言 在开发 Node.js 应用程序时,难免会涉及到一些需要调用外部程序的情况。为了保证我们编写的代码能够正常地与外部程序交互,我们需要对 Node.js 中的 child_process 模块进行...

    1 年前

相关推荐

    暂无文章