我的编程空间,编程开发者的网络收藏夹
学习永远不晚

通过Java讲解ThreadPool线程池的示例

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

通过Java讲解ThreadPool线程池的示例

这篇文章主要为大家展示了通过Java讲解ThreadPool线程池的示例,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带大家一起来研究并学习一下“通过Java讲解ThreadPool线程池的示例”这篇文章吧。

Java的特点有哪些

Java的特点有哪些1.Java语言作为静态面向对象编程语言的代表,实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。2.Java具有简单性、面向对象、分布式、安全性、平台独立与可移植性、动态性等特点。3.使用Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。

ThreadPool线程池

  • 线程池的优势

    • 1.引言

    • 为什么要使用线程池

  • 线程池的使用

    • 2.1.newFixedThreadPool(int)方法

    • 2.2.newSingleThreadExector

    • 2.3.newCachedThreadPool

    • 1.架构说明

    • 2.线程池的三大方法

  • ThreadPoolExecutor底层原理

  • 线程池7大重要参数

1.线程池的优势

1.1.引言

与数据库线程池类似,如果没有数据库连接池,那么每次对数据库的连接池都要new来获取连接池。重复的连接和释放操作会消费大量的系统资源,我们可以使用数据库连接池,直接去池中取连接池。
同样,在没有线程池之前,我们也是通过new Thread.start()来获取线程,现在我们也不需要new了,这样就能实现复用,使得我们系统变得更加高效。

1.2.为什么要使用线程池

例子:

  • 10年前单核CPU电脑,假的多线程,像马戏团小丑玩多个球,CPU需要来回切换。

  • 现在是多核电脑,多个线程各自跑在独立的CPU上,不用切换效率高。

线程池的优势:

线程池做的工作只要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。

它的主要特点为:

  • 线程复用

  • 控制最大并发数

  • 管理线程

优点:

  • 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的销耗。

  • 第二:提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行。

  • 第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

2.线程池的使用

2.1.架构说明

Executor 框架是什么?

Java Doc中是这么描述的

An object that executes submitted Runnable tasks. This interface provides a way of decoupling task submission from the mechanics of how each task will be run, including details of thread use, scheduling, etc. An Executor is normally used instead of explicitly creating threads.

执行提交的Runnable任务的对象。这个接口提供了一种将任务提交与如何运行每个任务的机制,包括线程的详细信息使用、调度等。通常使用Executor而不是显式地创建线程。

Java中的线程池是通过Executor框架实现的,,该框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor这几个类。而我们常用的接口是ExecutorService子接口Executors是线程的工具类(类似数组的工具类Arrays,集合的工具类Collections)ThreadPoolExecutor是这些类的重点我们可以通过辅助工具类Executors拿到ThreadPoolExecutor线程池
通过Java讲解ThreadPool线程池的示例
各个类更加详细的介绍如下:

Executor所有线程池的接口,只有一个方法,该接口定义执行Runnable任务的方式
ExecutorService 增加Executor的行为,是Executor实现类的最直接的接口,该接口定义提供对Executor的服务
Executors 线程池工厂类,提供了一系列工厂方法用于创建线程池,返回的线程池都实现了
ScheduledExecutorService:定时调度接口。
AbstractExecutorService 执行框架抽象类。
ThreadPoolExecutor JDK中线程池的具体实现,一般用的各种线程池都是基于这个类实现的

2.2.线程池的三大方法

2.2.1.newFixedThreadPool(int)方法

Exectors.newFixedThreadPool(int) -->执行长期任务性能好,创建一个线程池,一池有N个固定的线程,有固定线程数的线程

public static void main(String[] args) {//一池5个受理线程,类似一个银行5个受理窗口。不管你现在多少个线程,都只有5个ExecutorService threadPool=Executors.newFixedThreadPool(5); try {//模拟有10个顾客过来银行办理业务,目前池子里面有5个工作人员提供服务。for(int i=1;i<=10;i++){//execute方法里面有一个参数,参数类型是Runnable,Runnable是函数式接口,可以用lambda表达式,并且runnable就是这10个顾客threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t 办理业务");});}} catch (Exception e) {// TODO: handle exception}finally{threadPool.shutdown();}}

通过Java讲解ThreadPool线程池的示例
可以看到执行结果。池子中有5个线程,相当于5个工作人员对外提供服务,办理业务。图中1号窗口办理了两次业务,银行的受理窗口可以多次被复用。也不一定是每个人办理两次,而是谁办理的快谁就办理的多。

当我们再线程执行的过程中加400ms的延迟,可以看看效果

public static void main(String[] args) {//一池5个受理线程,类似一个银行5个受理窗口。不管你现在多少个线程,都只有5个ExecutorService threadPool=Executors.newFixedThreadPool(5); try {//模拟有10个顾客过来银行办理业务,目前池子里面有5个工作人员提供服务。for(int i=1;i<=10;i++){//execute方法里面有一个参数,参数类型是Runnable,Runnable是函数式接口,可以用lambda表达式,并且runnable就是这10个顾客threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t 办理业务");});try {TimeUnit.MILLISECONDS.sleep(400);} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}} catch (Exception e) {// TODO: handle exception}finally{threadPool.shutdown();}}

通过Java讲解ThreadPool线程池的示例
此时说明网络拥堵的情况下或者办理业务比较慢,则线程池办理业务任务分配情况比较平均。

2.2.2.newSingleThreadExector

Exectors.newSingleThreadExector()–>一个任务一个任务的执行,一池一线程

public static void main(String[] args) {//一池一个工作线程,类似一个银行有1个受理窗口ExecutorService threadPool=Executors.newSingleThreadExecutor(); try {//模拟有10个顾客过来银行办理业务for(int i=1;i<=10;i++){//execute方法里面有一个参数,参数类型是Runnable,Runnable是函数式接口,可以用lambda表达式,并且runnable就是这10个顾客threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t 办理业务");});}} catch (Exception e) {// TODO: handle exception}finally{threadPool.shutdown();}}

通过Java讲解ThreadPool线程池的示例

2.2.3.newCachedThreadPool

Exectors.newCachedThreadPool()–>执行很多短期异步任务,线程池根据需要创建新线程,但在先前构建的线程可用时将重用他们。可扩容,遇强则强。一池n线程,可扩容,可伸缩,cache缓存的意思
那么池的数量应该设置多少呢,如果银行只有一个窗口,那么当人来得太多了,就忙不过来。如果银行有很多个窗口,但是人来的少,此时又显得浪费资源。那么如何该合理安排呢?这就需要用到newCachedThreadPool()方法,可扩容,可伸缩

public static void main(String[] args) {//一池一个工作线程,类似一个银行有n个受理窗口ExecutorService threadPool=Executors.newCachedThreadPool(); try {//模拟有10个顾客过来银行办理业务for(int i=1;i<=10;i++){//execute方法里面有一个参数,参数类型是Runnable,Runnable是函数式接口,可以用lambda表达式,并且runnable就是这10个顾客threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t 办理业务");});}} catch (Exception e) {// TODO: handle exception}finally{threadPool.shutdown();}}

通过Java讲解ThreadPool线程池的示例

public static void main(String[] args) {//一池一个工作线程,类似一个银行有n个受理窗口ExecutorService threadPool=Executors.newCachedThreadPool(); try {//模拟有10个顾客过来银行办理业务for(int i=1;i<=10;i++){try{TimeUnit.SECONDS.sleep(1);}catch(InterruptedException e){e.printStackTrace();}//execute方法里面有一个参数,参数类型是Runnable,Runnable是函数式接口,可以用lambda表达式,并且runnable就是这10个顾客threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t 办理业务");});}} catch (Exception e) {// TODO: handle exception}finally{threadPool.shutdown();}}

通过Java讲解ThreadPool线程池的示例

3.ThreadPoolExecutor底层原理

newFixedThreadPool底层源代码

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

可以看到,底层的参数包含LinkedBlockingQueue阻塞队列。

newSingleThreadExecutor底层源代码

public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1, 1,                                    0L, TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue<Runnable>()));    }

newCachedThreadPool底层源代码

public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue<Runnable>());    }

SynchronousQueue这个阻塞队列是单一版阻塞队列,阻塞队列的容量为1.

这3个方法其实都共同返回了一个对象,即ThreadPoolExecutor的对象

4.线程池7大重要参数

ThreadPoolExecutor的构造函数

public ThreadPoolExecutor(int corePoolSize,                              int maximumPoolSize,                              long keepAliveTime,                              TimeUnit unit,                              BlockingQueue<Runnable> workQueue,                              ThreadFactory threadFactory,                              RejectedExecutionHandler handler) {        if (corePoolSize < 0 ||            maximumPoolSize <= 0 ||            maximumPoolSize < corePoolSize ||            keepAliveTime < 0)            throw new IllegalArgumentException();        if (workQueue == null || threadFactory == null || handler == null)            throw new NullPointerException();        this.acc = System.getSecurityManager() == null ?                null :                AccessController.getContext();        this.corePoolSize = corePoolSize;        this.maximumPoolSize = maximumPoolSize;        this.workQueue = workQueue;        this.keepAliveTime = unit.toNanos(keepAliveTime);        this.threadFactory = threadFactory;        this.handler = handler;    }

上面的int corePoolSize,int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue workQueue,ThreadFactory threadFactory,
RejectedExecutionHandler handler即我们的七大线程参数
上面是ThreadPoolExecutor类的构造方法,有7大参数:

1)corePoolSize:线程池中的常驻核心线程数,简称核心数。
比如说,一个线程池我们可以把它当作银行的网点,银行只要开门,就必须至少有一个人在值班,这个就叫常驻核心线程数。比如如果某个银行周一到周五五个网点全开,那么周一到周五的常驻核心线程数为5.如果今天业务没有那么频繁,窗口为1,那么今天的常驻核心线程数就是1

2)maxImumPoolSize:线程池中能够容纳同时执行的最大线程数,此值必须大于等于1

3)keepAliveTime:多余的空闲线程的存活时间,当前池中线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余线程会被销毁直到剩下corePoolSize为止
如果线程池中有常驻线程数,又有最大线程数,说明平时是用常驻的,工作紧张了,它会扩容到最大线程数,如果业务降下来了,我们设置了多余的空闲线程的存活时间,比如设置30s,如果30s都没有多余的请求过来,有些银行就会关闭窗口,所以它不仅会扩大还会缩小。

4)unit:keepAliveTime的单位
单位:是秒,毫秒,微秒。

5)workQueue:任务队列,被提交但尚未被执行的任务
这是一个阻塞队列,比如说银行,只有3个受理窗口,而来了4个客户。这个阻塞队列就是银行的候客区,来了客户不能让他走了。窗口数控制了线程的并发数。

6)threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般默认即可
线程都是统一的创建。线程池里面有已经new好的线程,这些由线程池工厂生产。

7)handler:拒绝策略,表示当前队列满了,并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝请求执行的runnable的策略

比如说今天银行客流高峰,三个窗口都满了,候客区也满了。我们没有选择继续拉人,因为不安全我们选择委婉的拒绝。

以上就是关于“通过Java讲解ThreadPool线程池的示例”的内容,如果改文章对你有所帮助并觉得写得不错,劳请分享给你的好友一起学习新知识,若想了解更多相关知识内容,请多多关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

通过Java讲解ThreadPool线程池的示例

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

通过Java讲解ThreadPool线程池的示例

这篇文章主要为大家展示了通过Java讲解ThreadPool线程池的示例,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带大家一起来研究并学习一下“通过Java讲解ThreadPool线程池的示例”这篇文章吧。Java的特点有
2023-06-06

Java并发线程池实例分析讲解

这篇文章主要介绍了Java并发线程池实例,线程池——控制线程创建、释放,并通过某种策略尝试复用线程去执行任务的一个管理框架,从而实现线程资源与任务之间一种平衡
2023-02-02

Java线程池的示例分析

小编给大家分享一下Java线程池的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!为什么需要线程池我们知道创建线程的常用方式就是 new Thread()
2023-06-22

Java中线程池的示例分析

小编给大家分享一下Java中线程池的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java线程池线程的缺点:1.线程的创建它会开辟本地方法栈、JVM栈、程
2023-06-20

Java中四种线程池的使用示例详解

在什么情况下使用线程池? 1.单个任务处理的时间比较短 2.将需处理的任务的数量大使用线程池的好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销 2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换”
2023-05-31

Java中线程组ThreadGroup与线程池的区别及示例

这篇文章主要介绍了Java中线程组与线程池的区别及示例,ThreadGroup是用来管理一组线程的,可以控制线程的执行,查看线程的执行状态等操作,方便对于一组线程的统一管理,需要的朋友可以参考下
2023-05-19

Java并发编程之线程池的示例分析

这篇文章将为大家详细讲解有关Java并发编程之线程池的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。什么是线程池是一种基于池化思想管理线程的工具。池化技术:池化技术简单点来说,就是提前保存大量的资
2023-06-20

Java多线程之线程池七个参数的示例分析

这篇文章主要介绍Java多线程之线程池七个参数的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!ThreadPoolExecutor是JDK中的线程池实现,这个类实现了一个线程池需要的各个方法,它提供了任务提交
2023-06-14

Java实现手写一个线程池的示例代码

线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和细节吗?本文就来通过手写一个简单的线程池框架,去掌握线程池的基本原理,感兴趣的可以学习一下
2022-11-13

Java实现手写乞丐版线程池的示例代码

在这篇文章当中我们主要介绍实现一个非常简易版的线程池,深入的去理解其中的原理,麻雀虽小,五脏俱全,感兴趣的小伙伴快跟随小编一起学习学习吧
2022-11-13

java 打造阻塞式线程池的实例详解

java 打造阻塞式线程池的实例详解原来以为tiger已经自带了这种线程池,就是在任务数量超出时能够阻塞住投放任务的线程,主要想用在JMS消息监听。开始做法:在ThreadPoolExcecutor中代入new ArrayBlockingQ
2023-05-31

MySQL存储过程的传参和流程控制示例讲解

这篇文章主要介绍了MySQL存储过程的传参和流程控制示例讲解, repeat和Loop区别是repeat有自己退出循环的语句until,Loop使用的是if判断语句,本文结合示例代码详细讲解,需要的朋友可以参考下
2023-02-10

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录