当前位置: 首页 > news >正文

Java多线程之线程池,volatile,悲观锁,乐观锁,并发工具类

目录

  • 1.线程池核心原理
    • 1.创建线程池
    • 2.任务拒绝策略
    • 3.自定义线程池
  • 2.线程池的大小
    • 1.最大并行数
    • 2.影响线程池大小的因素
  • 3.多线程常见考点(volatile,悲观锁,乐观锁)
  • 4.并发工具类

1.线程池核心原理

①创建一个空的池子
②提交任务时,尺子会创建新的线程对象,任务执行完毕后,线程会归还给池子。
下次提交任务时,就不需要创建新的线程,直接复用已有的线程即可。
③但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待。

1.创建线程池

Executors:线程池工具类通过调用方法返回不同类型的线程池对象。

在这里插入图片描述
创建一个上限为3的线程池:

public class Main{public static void main(String[] args) {//获取线程池对象ExecutorService pools = Executors.newFixedThreadPool(3);//提交任务pools.submit(new MyRunnable());pools.submit(new MyRunnable());pools.submit(new MyRunnable());//销毁线程池pools.shutdown();}
}

2.任务拒绝策略

自定义线程池执行优先级分贝为:核心线程,临时线程,阻塞队列。

在这里插入图片描述

3.自定义线程池

public class Main{public static void main(String[] args) {//创建自定义线程池ThreadPoolExecutor pool = new ThreadPoolExecutor(3,//核心线程数量,不能小于06,//最大线程数,要大于核心线程数60,//空闲线程最大存活时间TimeUnit.SECONDS,//时间单位new ArrayBlockingQueue<>(3),//任务队列Executors.defaultThreadFactory(),//创建线程工厂new ThreadPoolExecutor.AbortPolicy()//任务拒绝策略);}
}

2.线程池的大小

1.最大并行数

最大并行数指的是在线程池中同时执行的最大线程数量。
当线程池中的活动线程数量达到最大并行数时,新的任务会进入等待队列,直到有可用的线程资源。
通过控制最大并行数,可以有效地管理线程池的负载,避免过多的并发线程导致系统资源耗尽。

查看电脑的最大线程数量

        //利用java虚拟机查看可用处理器的数目System.out.println(Runtime.getRuntime().availableProcessors());

2.影响线程池大小的因素

根据项目的运算需求决定:
CPU密集型运算:
线程池大小 = 最大并行数 + 1 线程池大小=最大并行数+1 线程池大小=最大并行数+1
I/O密集型运算:
最大并行数 ∗ 期望 C P U 利用率 ∗ 总时间( C P U 计算时间 + 等待时间) C P U 计算时间 最大并行数*期望CPU利用率*\frac{总时间(CPU计算时间+等待时间)}{CPU计算时间} 最大并行数期望CPU利用率CPU计算时间总时间(CPU计算时间+等待时间)

3.多线程常见考点(volatile,悲观锁,乐观锁)

volatile关键字
volatile是一个Java关键字,用于修饰变量。
当一个变量被声明为volatile时,意味着这个变量的值可能会被多个线程同时修改。
volatile关键字的作用是告诉编译器和JVM,对于这个变量的读写操作不能进行重排序,且每次读取该变量时都必须从内存中读取最新的值,而不是使用缓存。
这样可以保证多个线程能够正确地读取到最新的值,从而避免了数据不一致的问题。

悲观锁
悲观锁是一种线程同步机制,用于确保在多线程环境下对共享资源的安全访问。
悲观锁的基本思想是假设在未来的某个时间点会有其他线程来访问共享资源,因此通过阻塞和限制其他线程的访问以确保数据的一致性和完整性
在悲观锁的实现中,当一个线程访问共享资源时,会将该资源加锁,以阻塞其他线程对该资源的访问。
只有当当前线程完成对资源的操作后,其他线程才能获取到锁,然后才能访问资源。
悲观锁的特点是,在多线程环境下会频繁地加锁和释放锁,这会导致线程切换的开销增加。
因此,悲观锁适用于对共享资源的访问频率较低的情况,以减少线程之间的竞争。
常见的悲观锁实现包括互斥锁(Mutex)和读写锁(ReadWriteLock)。
互斥锁可以确保同一时间只有一个线程能够访问共享资源,而读写锁在读操作时允许多个线程同时访问共享资源,在写操作时只允许一个线程访问

乐观锁
乐观锁是一种并发控制机制,它假设多个线程之间很少会发生冲突,因此不会进行显式的加锁操作,而是通过一种乐观的方式进行并发访问。

在乐观锁机制中,线程在读取数据时,不会对数据进行加锁,而是先读取数据的版本号,然后在对数据进行修改时,再次检查版本号是否发生变化。
如果版本号没有变化,说明其他线程没有修改过数据,当前线程可以进行修改,并更新版本号;如果版本号发生了变化,说明其他线程已经修改过数据,当前线程需要重新读取数据,然后再次尝试修改。
乐观锁相对于悲观锁来说,减少了对数据的加锁和解锁操作,因此在高并发场景下,乐观锁的性能通常比悲观锁更好
但是,由于乐观锁需要进行额外的版本号检查和数据重读操作,因此如果冲突较多,可能会导致性能下降。

4.并发工具类

ConcurrentHashMap
ConcurrentHashMap是Java中的一个线程安全的哈希表,它用于在多线程环境下进行并发访问的操作。
它提供了一种高效的方式来存储和操作键值对
ConcurrentHashMap的主要作用是在多线程环境中提供安全的并发访问
它通过使用分段锁(Segment)来提高并发情况下的性能。
每个Segment可以理解为一个独立的哈希表,不同的线程可以同时访问不同的Segment,从而减小了锁的粒度,提高了并发性能。

CountDownLatch
CountDownLatch是一个并发辅助类,它可以使一个或多个线程等待其他线程完成操作后再继续执行
在Java多线程中,CountDownLatch的作用是控制线程的执行顺序
当一个或多个线程需要等待其他线程完成某些操作后再继续执行时,可以使用CountDownLatch来实现。

CyclicBarrier
CyclicBarrier(循环屏障)是Java多线程中的一个同步工具类,用于控制线程的执行顺序和并发同步。
它可以让一组线程在某个点上等待,直到所有线程都达到这个点,然后执行后续操作

Semaphore
在Java多线程中,Semaphore(信号量)是一种用于控制同时访问特定资源(如线程数)的机制。
它可以用来限制同一时间内可以访问某个资源的线程数量

ExChanger
Exchanger是Java多线程中的一个工具类,用于线程之间的数据交换
它提供了一个同步点,在这个同步点上,两个线程可以交换彼此的数据。
具体来说,Exchanger有一个exchange方法,当一个线程调用exchange方法时,它会被阻塞,直到另一个线程也调用了exchange方法。
然后两个线程会交换彼此的数据,并继续执行。

相关文章:

  • 机器学习之BP神经网络精讲(Backpropagation Neural Network(附案例代码))
  • 基于SpringBoot的在线互动学习网站
  • git上传代码到github远程仓库
  • 个人博客主题 vuepress-hope
  • ubuntu 如何放开防火墙端口,ubuntu 防火墙操作命令,ubuntu 防火墙全面操作说明
  • python读取xlsx格式的excel
  • Python面向对象-三大特性
  • MySQL基础笔记(1)基础理论
  • Python编程-面向对象基础与入门到实践一书的内容拓展
  • 【机电、机器人方向会议征稿|不限专业|见刊快】2024年机械、 图像与机器人国际会议(IACMIR 2024)
  • asp.net core webapi AutoMapper使用
  • 抖音详情API:从零开始构建抖音应用
  • Python教程(19)——python异常处理
  • 云计算:OpenStack 配置云主机实例的资源实现内网互通
  • 信创之国产浪潮电脑+统信UOS Linux操作系统体验10:visual studio code中调试C++程序
  • Angular Elements 及其运作原理
  • Bootstrap JS插件Alert源码分析
  • Date型的使用
  • github从入门到放弃(1)
  • JavaScript对象详解
  • oldjun 检测网站的经验
  • Spring声明式事务管理之一:五大属性分析
  • 近期前端发展计划
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 普通函数和构造函数的区别
  • 我的业余项目总结
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • ​力扣解法汇总1802. 有界数组中指定下标处的最大值
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #pragma multi_compile #pragma shader_feature
  • #Spring-boot高级
  • (02)vite环境变量配置
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (MATLAB)第五章-矩阵运算
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (四)Linux Shell编程——输入输出重定向
  • (转)http协议
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .Net Core 中间件验签
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .NET设计模式(8):适配器模式(Adapter Pattern)
  • .Net转Java自学之路—基础巩固篇十三(集合)
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d
  • @Bean注解详解
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • [ C++ ] STL_list 使用及其模拟实现
  • [Android Studio] 开发Java 程序
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]
  • [C++]STL之map
  • [DevEpxress]GridControl 显示Gif动画