Java线程池详解「建议收藏」

Java线程池详解「建议收藏」文章目录简介什么是线程池银行营业厅案例执行流程创建方式所有创建方式通过ThreadPoolExecutor创建简介什么是线程池线程池(ThreadPool)是一种基于池化思想管理和使用线程的机制。它是将多个线程预先存储在一个“池子”内,当有任务出现时可以避免重新创建和销毁线程所带来性能开销,只需要从“池子”内取出相应的线程执行对应的任务即可。常见的运用池化思想的有:内存池、数据库连接池。使用线程的优点如下:提高线程的利用率提高程序的相应速度便于统一管理线程对象银行营业厅案例假设银行正常可

大家好,又见面了,我是你们的朋友全栈君。

简介

什么是线程池

线程池(ThreadPool)是一种基于池化思想管理和使用线程的机制。它是将多个线程预先存储在一个“池子”内,当有任务出现时可以避免重新创建和销毁线程所带来性能开销,只需要从“池子”内取出相应的线程执行对应的任务即可。常见的运用池化思想的有:内存池、数据库连接池。使用线程池的优点如下:

  • 提高线程的利用率
  • 提高程序的相应速度
  • 便于统一管理线程对象

银行营业厅案例

假设银行正常可以同时给3个客户办理业务(绿色表示),最多可同时给5个用户办理业务(多余的用红色表示),等候区最多可以等待4个客户(用蓝色表示),小人表示客户。正常的营业厅处理业务流程如下图所示:
在这里插入图片描述
注:这个流程用于模拟线程池,和实际银行办理业务还是有点区别。

假设同时进来7个用户,办理业务效果如下:
在这里插入图片描述
4个等待区用户只有等前面的窗口办理完才能依次办理。

假设同时进来10个用户,办理业务效果如下:
在这里插入图片描述
第10个用户超出最大限度被拒绝办理业务,其余等待区用户只有等前面的窗口办理完才能依次办理,4和5号窗口超时后会重新进入空闲状态。

执行流程

上面案例中的正常办理业务窗口数对应线程池中的核心线程数,最多办理业务窗口数对应线程池中的最大线程数,等候区对应线程池中的阻塞(等待)队列。线程池关键节点的执行流程如下:

  • 当线程数小于核心线程数时,创建线程。
  • 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  • 当线程数大于等于核心线程数,且任务队列已满:若线程数小于最大线程数,创建线程;若线程数等于最大线程数,抛出异常,拒绝任务。

线程池的执行流程如下图所示:
在这里插入图片描述

参考链接

创建方式

所有创建方式

Java线程池一共有7种,按创建类分为两种:

  • 通过Executors类创建
    • Executors.newFixedThreadPool
      创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待
    • Executors.newCachedThreadPool
      创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程
    • Executors.newSingleThreadExecutor
      创建单个线程数的线程池,它可以保证先进先出的执行顺序
    • Executors.newScheduledThreadPool
      创建一个可以执行延迟任务的线程池
    • Executors.newSingleThreadScheduledExecutor
      创建一个单线程的可以执行延迟任务的线程池
    • Executors.newWorkStealingPool
      创建一个抢占式执行的线程池(任务执行顺序不确定)JDK 1.8 中添加
  • 通过ThreadPoolExecutor类创建
    最原始的创建线程池的方式,它包含了 7 个参数可供设置,后面会详细讲。

一般使用Java提供了创建线程池的接口Executor(),推荐用子类ThreadPoolExecutor来创建线程池。这在阿里巴巴《Java开发手册》中有说明:

【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool:允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

参考链接

通过ThreadPoolExecutor创建

该类参数最多的构造方法如下:

public ThreadPoolExecutor(int corePoolSize,
                         int maximumPoolSize,
                         long keepAliveTime,
                         TimeUnit unit,
                         BlockingQueue<Runnable> workQueue,
                         ThreadFactory threadFactory,
                         RejectedExecutionHandler handler) { 
   
                         // 省略相关代码
}

参数说明如下:

  • corePoolSize
    核心线程数
  • maximumPoolSize
    最大线程数
  • keepAliveTime
    最大线程数可以存活的时间,就是线程池中除了核心线程之外的其他的最长可以保留的时间,因为在线程池中,除了核心线程即使在无任务的情况下也不能被清除,其余的都是有存活时间的,意思就是非核心线程可以保留的最长的空闲时间
  • unit
    计算keepAliveTime的单位
  • workQueue
    阻塞(等待)队列。一共有ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue等7种阻塞队列
  • threadFactory
    创建线程的工厂,主要用来创建线程,默认为正常优先级、非守护线程。
  • handler
    拒绝策略。一共有下面四种:
    • AbortPolicy
      不执行新任务,直接抛出异常,提示线程池已满
    • DisCardPolicy
      不执行新任务,也不抛出异常
    • DisCardOldSetPolicy
      将消息队列中的第一个任务替换为当前新进来的任务执行
    • CallerRunsPolicy
      直接调用execute来执行当前任务

示例代码:

public class ThreadPoolTest { 
   
    public static void main(String[] args) { 
   
        ExecutorService executorService = new ThreadPoolExecutor(3,5,1L, TimeUnit.SECONDS,new ArrayBlockingQueue(4),Executors.defaultThreadFactory());
        for(int i=0;i<7;i++){ 
   
            executorService.execute(()->{ 
   
                System.out.println(Thread.currentThread().getName()+" "+"--->办理业务");
            });
        }
        executorService.shutdown();
    }
}

运行结果:

pool-1-thread-2 --->办理业务
pool-1-thread-1 --->办理业务
pool-1-thread-3 --->办理业务
pool-1-thread-1 --->办理业务
pool-1-thread-2 --->办理业务
pool-1-thread-1 --->办理业务
pool-1-thread-3 --->办理业务

当for循环中的i<10时运行结果:

pool-1-thread-2 --->办理业务
pool-1-thread-4 --->办理业务
pool-1-thread-2 --->办理业务
pool-1-thread-3 --->办理业务
pool-1-thread-3 --->办理业务
pool-1-thread-1 --->办理业务
pool-1-thread-5 --->办理业务
pool-1-thread-2 --->办理业务
pool-1-thread-4 --->办理业务
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.test.ThreadPoolTest$$Lambda$1/1209271652@7a79be86 rejected from java.util.concurrent.ThreadPoolExecutor@880ec60[Running, pool size = 5, active threads = 0, queued tasks = 0, completed tasks = 9]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at com.test.ThreadPoolTest.main(ThreadPoolTest.java:9)

可以发现只有9(最大+阻塞)个任务执行了,之后进来的任务会被拒绝。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/156214.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • dos命令中DATE:~0,10输出日期格式名称格式/改为-

    dos命令中DATE:~0,10输出日期格式名称格式/改为-1、问题原因系统日期格式为/分隔,dos命令中%DATE:~0,10%的日期将会被当作多个文件夹处理2、解决方法1)、在控制面板中时钟、语言和区域中或者桌面右下角调整日期和时间格式,更改日历设置,日期格式由原来是yyyy/M/d改成yyyy-M-d2)、通用写法(年月日分开取):%DATE:~0,10%替换为%date:~0,4%%date:~5,2%%date:~8,2%3)、提前变…

    2022年9月20日
    3
  • 使用MySQL Workbench建立数据库,建立新的表,向表中添加数据

    使用MySQL Workbench建立数据库,建立新的表,向表中添加数据初学数据库,记录一下所学的知识。我用的MySQL数据库,使用MySQLWorkbench管理。下面简单介绍一下如何使用MySQLWorkbench建立数据库,建立新的表,为表添加数据。  点击上图中的“加号”图标,新建一个连接,    如上图,先输入数据库的账号密码,帐号默认为root,填好密码后点击“OK”,连接就建立好了,建立完成后,会出现一个长方

    2022年9月24日
    3
  • lunix常用命令「建议收藏」

    lunix常用命令「建议收藏」文件管理命令ls      显示文件或目录   -l     列出文件详细信息l(list)   -a     列出当前目录下所有文件及目录,包括隐藏的a(all)mkdir    创建目录   -p     创建目录,若无父目录,则创建p(parent)cd   

    2022年10月3日
    2
  • Hadoop面试题总结「建议收藏」

    Hadoop面试题总结「建议收藏」Hadoop面试题总结1.hadoop的TextInputFormat作用是什么?如何自定义实现?InputFormat会在map操作之前对数据进行两方面的预处理:gitSplits,返回的是InputSplit数组,对数据进行split切片,每一个切片都需要一个map任务去处理。getRecordReader,返回的是RecordReader对象,将每个切片中的数据转换为<k…

    2022年6月16日
    31
  • 手机一键装windows系统_git could not create work tree

    手机一键装windows系统_git could not create work treeGit简介Git是目前世界上最先进的分布式版本控制系统。可以简单理解为一种管理的工具,通过git可以将github上的代码拉到本地或者把电脑里的代码push到github。Windows环境下Git的下载与安装地址:https://git-scm.com/download这里选择64位的下载完成后,双击即可进入安装界面选择自己想要安装的位置,默认C盘,这里选择了D盘一些组件:(这里选择在桌面上创建git的图标Additionalicons–OntheDesktop,其他的默认即

    2022年8月25日
    7
  • c# 连接数据库2 OleDbDataAdapter DataSet[通俗易懂]

    c# 连接数据库2 OleDbDataAdapter DataSet[通俗易懂]    privatevoidbutton2_Click(objectsender,EventArgse)    {      stringcon=@"Provider=Microsoft.Jet.OleDb.4.0;DataSource=fruit.mdb";      OleDbConnectiondbconn=newO…

    2025年7月23日
    2

发表回复

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

关注全栈程序员社区公众号