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

相关文章

Python中Tkinter GUI编程详细教程

《Python中TkinterGUI编程详细教程》Tkinter作为Python编程语言中构建GUI的一个重要组件,其教程对于任何希望将Python应用到实际编程中的开发者来说都是宝贵的资源,这篇文... 目录前言1. Tkinter 简介2. 第一个 Tkinter 程序3. 窗口和基础组件3.1 创建窗

线程池ThreadPoolExecutor应用过程

《线程池ThreadPoolExecutor应用过程》:本文主要介绍如何使用ThreadPoolExecutor创建线程池,包括其构造方法、常用方法、参数校验以及如何选择合适的拒绝策略,文章还讨论... 目录ThreadPoolExecutor构造说明及常用方法为什么强制要求使用ThreadPoolExec

Java线程池核心参数原理及使用指南

《Java线程池核心参数原理及使用指南》本文详细介绍了Java线程池的基本概念、核心类、核心参数、工作原理、常见类型以及最佳实践,通过理解每个参数的含义和工作原理,可以更好地配置线程池,提高系统性能,... 目录一、线程池概述1.1 什么是线程池1.2 线程池的优势二、线程池核心类三、ThreadPoolE

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程

python协程实现高并发的技术详解

《python协程实现高并发的技术详解》协程是实现高并发的一种非常高效的方式,特别适合处理大量I/O操作的场景,本文我们将简单介绍python协程实现高并发的相关方法,需要的小伙伴可以了解下... 目录核心概念与简单示例高并发实践:网络请求协程如何实现高并发:核心技术协作式多任务与事件循环非阻塞I/O与连接

深入理解Redis线程模型的原理及使用

《深入理解Redis线程模型的原理及使用》Redis的线程模型整体还是多线程的,只是后台执行指令的核心线程是单线程的,整个线程模型可以理解为还是以单线程为主,基于这种单线程为主的线程模型,不同客户端的... 目录1 Redis是单线程www.chinasem.cn还是多线程2 Redis如何保证指令原子性2.

C++实现一个简易线程池的使用小结

《C++实现一个简易线程池的使用小结》在现代软件开发中,多线程编程已经成为提升程序性能的常见手段,本文主要介绍了C++实现一个简易线程池的使用小结,感兴趣的可以了解一下... 在现代软件开发中,多线程编程已经成为提升程序性能的常见手段。无论是处理大量 I/O 请求的服务器,还是进行 CPU 密集型计算的应用

JDK21对虚拟线程的几种用法实践指南

《JDK21对虚拟线程的几种用法实践指南》虚拟线程是Java中的一种轻量级线程,由JVM管理,特别适合于I/O密集型任务,:本文主要介绍JDK21对虚拟线程的几种用法,文中通过代码介绍的非常详细,... 目录一、参考官方文档二、什么是虚拟线程三、几种用法1、Thread.ofVirtual().start(

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三