JUC并发编程-浅学浅用之线程池

2024-01-30 08:20

本文主要是介绍JUC并发编程-浅学浅用之线程池,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

11. 线程池(重点)

重点理解

线程池:三大方式、七大参数、四种拒绝策略,还有如何设置最大线程池的大小

池化技术

程序的运行,本质:占用系统的资源!我们需要去优化资源的使用 ===> 池化技术

线程池、JDBC的连接池、内存池、对象池 等等。。。。

资源的创建、销毁十分消耗资源

池化技术:事先准备好一些资源,如果有人要用,就来我这里拿,用完之后还给我,以此来提高效率。

1)线程池的好处:

1、降低资源的消耗;

2、提高响应的速度;

3、方便管理;

2)线程池:三大方法(工具类)

  • ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
  • ExecutorService threadPool2 = Executors.newFixedThreadPool(5); //创建一个固定的线程池的大小
  • ExecutorService threadPool3 = Executors.newCachedThreadPool(); //可伸缩的

在这里插入图片描述

不建议使用工具类,不允许使用Executors去创建,建议使用ThreadPoolExecutor方式创建

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

//工具类 Executors 三大方法;
public class Demo01 {public static void main(String[] args) {ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程ExecutorService threadPool2 = Executors.newFixedThreadPool(5); //创建一个固定的线程池的大小ExecutorService threadPool3 = Executors.newCachedThreadPool(); //可伸缩的//线程池用完必须要关闭线程池try {for (int i = 1; i <=100 ; i++) {//通过线程池创建线程threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+ " ok");});}} catch (Exception e) {e.printStackTrace();} finally {threadPool.shutdown();}}
}

3)七大参数

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.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;
}

在这里插入图片描述

阿里巴巴的Java操作手册中明确说明:对于Integer.MAX_VALUE初始值较大,所以一般情况我们要使用底层的ThreadPoolExecutor来创建线程池

在这里插入图片描述

public class PollDemo {public static void main(String[] args) {// 获取cpu 的核数int max = Runtime.getRuntime().availableProcessors();ExecutorService service =new ThreadPoolExecutor(2,max,3,TimeUnit.SECONDS,new LinkedBlockingDeque<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());try {for (int i = 1; i <= 10; i++) {service.execute(() -> {System.out.println(Thread.currentThread().getName() + "ok");});}}catch (Exception e) {e.printStackTrace();}finally {service.shutdown();}}
}

4)拒绝策略

在这里插入图片描述

new ThreadPoolExecutor.AbortPolicy(): //该拒绝策略为:银行满了,还有人进来,不处理这个人的,并抛出异常

超出最大承载,就会抛出异常:队列容量大小+maxPoolSize

new ThreadPoolExecutor.CallerRunsPolicy(): //该拒绝策略为:哪来的去哪里 main线程进行处理

new ThreadPoolExecutor.DiscardPolicy(): //该拒绝策略为:队列满了,丢掉异常,不会抛出异常。

new ThreadPoolExecutor.DiscardOldestPolicy(): //该拒绝策略为:队列满了,尝试去和最早的进程竞争,不会抛出异常

AbortPolicy()
在这里插入图片描述

CallerRunsPolicy()
在这里插入图片描述

DiscardPolicy()

在这里插入图片描述

DiscardOldestPolicy()

在这里插入图片描述

5)如何设置线程池的大小

1、CPU密集型:电脑的核数是几核就选择几;选择maximunPoolSize的大小

在这里插入图片描述

// 获取cpu 的核数int max = Runtime.getRuntime().availableProcessors();ExecutorService service =new ThreadPoolExecutor(2,max,3,TimeUnit.SECONDS,new LinkedBlockingDeque<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

2、I/O密集型:

在程序中有15个大型任务,io十分占用资源;I/O密集型就是判断我们程序中十分耗I/O的线程数量,大约是最大I/O数的一倍到两倍之间。

6)线程池demo

下面是一个使用ThreadPoolExecutor创建线程池的例子,涉及线程池的多种配置:

import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(2, // 核心线程数4, // 最大线程数10, // 空闲线程存活时间TimeUnit.SECONDS, // 存活时间的单位new ArrayBlockingQueue<>(5), // 任务队列Executors.defaultThreadFactory(), // 线程工厂new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略);// 提交任务给线程池for (int i = 0; i < 10; i++) {final int taskId = i;executor.submit(() -> {System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();}
}

上述例子中,使用ThreadPoolExecutor创建了一个线程池,参数配置如下:

1. 核心线程数:2,线程池会一直保持这些线程,即使它们是空闲的。
2. 最大线程数:4,线程池中最多同时执行的线程数量。
3. 空闲线程存活时间:10秒,如果线程池中的线程空闲时间超过该值,且当前线程数大于核心线程数,那么这个线程会被销毁。
4. 存活时间的单位:秒。
5. 任务队列:ArrayBlockingQueue,最多容纳5个任务的阻塞队列。
6. 线程工厂:Executors.defaultThreadFactory(),使用默认的线程工厂创建线程。
7. 拒绝策略:CallerRunsPolicy,当线程池无法执行新任务时,会将任务返回给调用者来执行。
然后,通过循环提交10个任务给线程池,并在每个任务中输出当前任务的ID和执行线程的名称。最后,调用shutdown()方法关闭线程池。

拓展:CPU密集型和IO密集型理解

CPU密集型(CPU-bound)
CPU密集型也叫计算密集型,指的是系统的硬盘、内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/内存),I/O在很短的时间就可以完成,而CPU还有许多运算要处理,CPU Loading很高。

**在多重程序系统中,大部份时间用来做计算、逻辑判断等CPU动作的程序称之CPU bound。**例如一个计算圆周率至小数点一千位以下的程序,在执行的过程当中绝大部份时间用在三角函数和开根号的计算,便是属于CPU bound的程序。

**CPU bound的程序一般而言CPU占用率相当高。**这可能是因为任务本身不太需要访问I/O设备,也可能是因为程序是多线程实现因此屏蔽掉了等待I/O的时间。

IO密集型(I/O bound)
IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。

**I/O bound的程序一般在达到性能极限时,CPU占用率仍然较低。**这可能是因为任务本身需要大量I/O操作,而pipeline做得不是很好,没有充分利用处理器能力。

CPU密集型 vs IO密集型

我们可以把任务分为计算密集型和IO密集型

计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数

计算密集型任务由于主要消耗CPU资源,因此,代码运行效率至关重要。Python这样的脚本语言运行效率很低,完全不适合计算密集型任务。 对于计算密集型任务,最好用C语言编写。

第二种任务的类型是IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。

IO密集型任务执行期间,99%的时间都花在IO上,花在CPU上的时间很少,因此,用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言,完全无法提升运行效率。对于IO密集型任务,最合适的语言就是开发效率最高(代码量最少)的语言,脚本语言是首选,C语言最差。

总之,计算密集型程序适合C语言多线程I/O密集型适合脚本语言开发的多线程

JUC并发编程-浅学浅用之线程池 到此完结,笔者归纳、创作不易,大佬们给个3连再起飞吧

这篇关于JUC并发编程-浅学浅用之线程池的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/659633

相关文章

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

Spring Boot3虚拟线程的使用步骤详解

《SpringBoot3虚拟线程的使用步骤详解》虚拟线程是Java19中引入的一个新特性,旨在通过简化线程管理来提升应用程序的并发性能,:本文主要介绍SpringBoot3虚拟线程的使用步骤,... 目录问题根源分析解决方案验证验证实验实验1:未启用keep-alive实验2:启用keep-alive扩展建

Python异步编程中asyncio.gather的并发控制详解

《Python异步编程中asyncio.gather的并发控制详解》在Python异步编程生态中,asyncio.gather是并发任务调度的核心工具,本文将通过实际场景和代码示例,展示如何结合信号量... 目录一、asyncio.gather的原始行为解析二、信号量控制法:给并发装上"节流阀"三、进阶控制

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

Java终止正在运行的线程的三种方法

《Java终止正在运行的线程的三种方法》停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作,停止一个线程可以用Thread.stop()方法,但最好不要用它,本文给大家介绍了... 目录前言1. 停止不了的线程2. 判断线程是否停止状态3. 能停止的线程–异常法4. 在沉睡中停止5

Java捕获ThreadPoolExecutor内部线程异常的四种方法

《Java捕获ThreadPoolExecutor内部线程异常的四种方法》这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感... 目录方案 1方案 2方案 3方案 4结论方案 1使用 execute + try-catch 记录

Nginx实现高并发的项目实践

《Nginx实现高并发的项目实践》本文主要介绍了Nginx实现高并发的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录使用最新稳定版本的Nginx合理配置工作进程(workers)配置工作进程连接数(worker_co

Spring Boot 中正确地在异步线程中使用 HttpServletRequest的方法

《SpringBoot中正确地在异步线程中使用HttpServletRequest的方法》文章讨论了在SpringBoot中如何在异步线程中正确使用HttpServletRequest的问题,... 目录前言一、问题的来源:为什么异步线程中无法访问 HttpServletRequest?1. 请求上下文与线