首页 > 编程语言 >Java线程池详解

Java线程池详解

时间:2024-09-06 17:53:12浏览次数:15  
标签:ExecutorService Java Callable 任务 详解 线程 执行 ThreadPoolExecutor

线程池解释

线程池采用了池化思想,能够有效的管理线程的生命周期,减少了每次获取资源的消耗,提高了资源的利用率。类似池化实现还有数据库连接池、HTTP连接池等

好处

  • 减少了线程创建和销毁的开销

  • 提高了响应速度

  • 使得线程更加方便管理

常见使用场景

  • 量大处理时间较短的任务:有效利用线程池减少线程创建销毁的消耗

  • 需要限制线程数量时:线程越多对资源的消耗越大,线程池可以设置最大线程数进行限制

  • 异步执行一批不需要立刻反馈结果的任务:异步执行任务,减少系统响应时间

线程池的引入:Executor框架

Executor框架为Java 5 引入,将传统线程的操控方法进行优化升级,使其针对不同 场景更加的灵活、管理更加的方便,其核心jar包为java.util.concurrent,简称JUC。此外,很重要的一点,该框架还避免了 this逃逸问题。

this逃逸:指在构造函数返回之前,其他线程持有了该对象的引用,此时引用该对象调用其方法时,可能会出现不好排查的异常。

Executor框架主要包括三个部分

  • 任务:Runnabale/Callable,可以被 ThreadPoolExecutor 或 ScheduledThreadPoolExecutor(继承ThreadPoolExecutor) 执行

  • 执行:通过实现Executor接口的子接口ExecutorService去构造相对来说比较完整的线程池执行系统

  • 返回值:线程池的优势之一,通过实现Futrure接口的FutureTask 类将异步执行的结果获取到

  • 主线程创建 Runnable 或者 Callable 的任务对象,然后把 实现的 Runnbale 或者 Callable 交给 ExecutorService 执行:ExecutorService.execute(Runnable command) 或者 把 Runnable对象或者 Callable 对象提交给 ExecutorService 执行(ExecutorService.submit(Runnable command)

  • 如果执行 ExecutorService.submit()ExecutorService 返回一个实现了 Future 接口的对象(submit() 会返回一个 FuturesTask对象,FutureTask 实现了 Runnable,可以创建FutureTask,然后直接交给 ExecutorService执行;execute 则会把异常打印出来)

  • 最后,主线程执行 FuturesTask.get() 方法等待任务执行完成。也可以通过 FutureTask.cancel(boolean mayInterruptIfRunning) 来取消此任务执行。

ThreadPoolExecutor为例,ThreadPoolExecutor继承了AbstractExecutorService(抽象函数)的submit方法,并且实现了AbstractExecutorService来自Executor接口的execute方法,因此在调用线程池的submit方法时就会通过ThreadPoolExecutorexecute将任务(Runnabale/Callable为核心的RunnableFuture对象)加到工作队列中(addWorker方法实现),返回值则通过RunnableFuture对象的形式返回。

简单来说就是主线程将Runnabale/Callable对象通过submit方法提交给线程池,线程池通过内部调度按照不同的策略执行多线程任务,然后通过返回的Futrure对象的get方法取出执行结果。

ThreadPoolExecutor 类

线程池实现类 ThreadPoolExecutor 是 Executor 框架最核心的类

主线程提交任务后

  • 第一步,判断核心线程池线程数是否已满,若未满则创建线程,若已满则进入第二步

  • 第二步,判断等待队列是否已满,若未满则加入队列,若已满则进入第三步

  • 第三步,判断最大线程数是否已满,若未满则创建线程,若已满则根据设定的拒绝策略处理

参数介绍:

  • corePoolSize:核心线程数,能第一时间处理的线程数

  • maximumPoolSize:最大线程数,当核心线程池以及队列都满了的时候,线程池就会扩充到最大线程数

  • workQueue: 当核心线程池已满时,队列可以用来暂存后边进来的任务

  • keepAliveTime:线程数量大于核心线程数量时,线程闲置时间超过此值的线程会被回收掉,直至缩到核心线程数

  • unitkeepAliveTime 参数的时间单位

  • threadFactory:线程工厂,executor 创建线程时用到

  • handler:拒绝策略线程池已达到最大线程数,此时队列也满了,再有任务进来就会触发拒绝策略

拒绝策略:

  • AbortPolicy:拒绝任务并抛异常RejectedExecutionException

  • CallerRunsPolicy:直接在调用线程中执行任务,影响性能

  • DiscardPolicy:拒绝任务,不报异常,不做任何处理

  • DiscradOldestPolicy:拒绝掉最早的任务,执行最新的

线程池相关的内容有很多,该文章重在介绍,若要深究其中的某个元素,可以通过参考源码的方式,这样可以最直观的看到内部组成以及各个元素之间如何合作解决线程池的实现问题。

文章转载自:交给时间

原文链接:https://www.cnblogs.com/zyyjgsj/p/18369916

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

标签:ExecutorService,Java,Callable,任务,详解,线程,执行,ThreadPoolExecutor
From: https://blog.csdn.net/kfashfasf/article/details/141955771

相关文章

  • 一次Java性能调优实践【代码+JVM 性能提升70%】
    这是我第一次对系统进行调优,涉及代码和JVM层面的调优。如果你能看到最后的话,或许会对你日常的开发有帮助,可以避免像我一样,犯一些低级别的错误。本次调优的代码是埋点系统中的报表分析功能,小公司,开发结束后,没有CodeReview环节,所以下面某些问题,也许在CodeReview环节就可以避免......
  • postgresql java jdbc 负载均衡解决方案
    在PostgreSQL和JavaJDBC的环境中实现负载均衡,可以有效提升数据库性能和可用性。以下是一个基于PostgreSQL和JavaJDBC的负载均衡解决方案,包括主从复制、连接池、以及负载均衡器的集成。1.PostgreSQL主从复制PostgreSQL的主从复制是实现读写分离的重要前提。主节点(Ma......
  • android从java/kotlin层传递bitmap给jni并使用其像素
    一、概述在做jni开发的时候,有些情况下会直接通过java/kotlin层传递bitmap给jni,并取出其数据进行利用。例如:OpenGLES绘制纹理、保存像素图片等。二、代码示例1.在cmake中引入可以操作jni层BitmapInfo的libjnigraphics-landroid2.导入头文件#in......
  • JAVA反射机制【超详细!!】
    JAVA反射机制反射的概述JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。反射就是把java类中的各种成分映射成一个个......
  • JAVA网络编程之InetAddress 和 SocketAddress 的区别
    InetAddress和SocketAddress是Java网络编程中常用的类,用于处理网络连接中的地址信息。1.InetAddressInetAddress用于表示IP地址,既可以是IPV4也可以是IPV6。它可以用来获取主机的IP地址,或根据IP地址查找主机名。InetAddress是抽象类,常用的有两个子类:Inet4Address和I......
  • Leetcode算法挑战:详解如何实现交替合并字符串的解题思路
    Leetcode算法挑战中的“交替合并字符串”问题,要求我们将两个字符串以交替的方式合并,终形成一个新的字符串。乍一看,这道题目似乎不复杂,但要写出高效且简洁的解法,还需要一定的思路和技巧。一、问题描述题目要求给定两个字符串word1和word2,将它们按照索引依次交替合并。如果某个......
  • JavaScript中的Object.freeze()和Object.seal()
    一、Object.freeze()1.简介:Object.freeze()是一个可以将对象冻结的方法。一旦对象被冻结,就不能添加、删除或修改其属性。这在需要确保对象完整性、防止任何意外或故意更改的场景中非常有用constperson={name:'Alice',age:30};Object.freeze(person);p......
  • 若依框架登录鉴权详解(动态路由)
     编辑若依框架登录鉴权:1.获取token(过期在响应拦截器中实现),2.基于RBAC模型获取用户、角色和权限信息(在路由前置守卫),3.根据用户权限动态生成(从字符串->组件,根据permission添加动态路由信息)和添加路由addRoutes(在路由前置守卫)若依框架(Ruoyi)后端的登录权限身份认证流程是一个复杂但高......
  • 搜索算法之二分搜索详细解读(附带Java代码解读)
    1.基本概念二分搜索(BinarySearch)是一种高效的查找算法,用于在一个已排序的数组中查找特定元素。它通过逐步将搜索范围减少一半来实现搜索,从而比线性搜索更快。由于它利用了数组的有序性,能够在对数时间内完成搜索操作。2.工作原理二分搜索的基本思想是:初始化:设置两个指针......
  • JavaScript 循环语句
    1. for 循环for循环是最常用的循环结构之一,它适合在循环开始前就知道循环次数的情况。基本语法for(初始化表达式;条件表达式;迭代后表达式){//循环体//这里的代码会在每次迭代时执行}如何工作初始化:首先执行初始化表达式,通常用来设置循环控制变量。条件......