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

PXM的JAVA并发编程学习总结

进程与线程

进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。

在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程。

线程与进程类似,但是是一个更小的执行单位,一个进程运行时可以产生多个线程,但是同一个进程的线程之间会共享堆和方法区,而进程与进程之间时相互隔离的。

所以系统创建和运行线程的开销比进程小很多。

Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态:

  • NEW: 初始状态,线程被创建出来但没有被调用 start() 。
  • RUNNABLE: 运行状态,线程被调用了 start()等待运行的状态。
  • BLOCKED:阻塞状态,需要等待锁释放。
  • WAITING:等待状态,表示该线程需要等待其他线程做出一些特定动作(通知或中断)。
  • TIME_WAITING:超时等待状态,可以在指定的时间后自行返回而不是像 WAITING 那样一直等待。
  • TERMINATED:终止状态,表示该线程已经运行完毕

volatile

volatile关键字能够保证变量的可见性,如果声明了volatile关键字,每次都会从主内存中获取变量。本质原因时它禁用了cpu缓存,因为cpu缓存中的L1,L2级缓存时不共享的,所以才会造成同一个变量在不同线程读到的值可能不一致,因此禁用,让它们全部实时对共享的主内存进行修改即可。还有一个重要的特性就是volatile通过内存屏障,能够防止指令重排。这个的主要应用参考单例模式双重检查锁,如果有一个线程发现单例已经不为null了,并开始调用,如果没加volatile,那么可能由于指令重排,这个单例的创建变成了先建立引用,再初始化,此时由于初始化尚未完成,容易引发未知问题。当然,它不能保证操作的原子性,进行并发写的时候仍然会出问题。

synchronized

synchronized可以保证用它修饰的方法或者代码块同时只有一个线程在运行,对于语句块,内部基于monitor相关指令和对象头实现,monitor是JVM的内置锁,通过争抢monitor来确保只有一个线程能进入。对于方法,用的则是ACC_SYNCHRONIZED,用于标记这个方法是一个同步方法。

synchronized会随着锁竞争的加剧自动进行锁升级,因为在低竞争环境下,中止线程并唤醒的成本显然较高,轻量级锁更优,在高竞争环境下,显然让大量线程自旋等待容易导致资源被耗尽。因此,锁会经历如下过程:无锁->偏向锁->轻量锁->自旋锁,在后续版本(jdk15),偏向锁逐渐被淘汰了,由于现在的锁往往是多线程竞争而不是同一线程反复调用,因此偏向锁往往是负优化。

  • volatile 关键字是线程同步的轻量级实现,所以 volatile性能肯定比synchronized关键字要好 。但是 volatile 关键字只能用于变量而 synchronized 关键字可以修饰方法以及代码块 。
  • volatile 关键字能保证数据的可见性,但不能保证数据的原子性。synchronized 关键字两者都能保证。
  • volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized 关键字解决的是多个线程之间访问资源的同步性。

ReentrantLock

ReentrantLock是一个可重入的独占锁,是对AQS框架的一个实现。相比syncornized增加了轮询、超时、中断、公平锁和非公平锁等高级功能,通过对AQS的state变量进行维护实现可重入。和syncornized不同的地方在于它有更多高级功能,并且是JDK层面的锁,而syncornized是由JVM实现的。唯一需要注意的是它要显式调用lock() 和 unlock(),使用不当可能产生死锁,一般通过try-catch调用,并放在finally里面解锁。

Threadlocal

Threadlocal类可以让每个线程读取同一个对象的同一个属性,都有相互独立的不同副本,可以避免数据竞争问题,它的核心实现逻辑在于通过把Threadlocal本身的引用和要被传入的属性组成一对Entry,其中Threadlocal本身的虚引用是Key,被传入的属性是value。因为Key是弱引用,所以当发生gc的时候会把它回收,所以如果没有了其它Threadlocal强引用,进行gc的时候会将Key也就是Threadlocal给回收掉。这样就不会导致污染后续使用者了。

Threadlocal有一个内部类叫做threadlocalMap,其中Threadlocal产生的entry就存在这里,每个线程的这个是唯一的,通过Threadlocal对象就能查找到当前线程的Threadlocal修饰的数据。

Threadlocal虽然很好,但是也有一些缺点。诸如内存泄露,因此你最好在执行结束的时候释放所有和当前线程有关的Threadlocal,必须通过try-catch调用并在finally代码块中手动调用remove。如果是公有的Threadlocal,最好加上final static关键字防止threadlocal被多次实例化。

Threadlocal和公共的ConcurrentHashMap最大的不同就是Threadlocal只负责储存私有信息,ConcurrentHashMap会共享给所有对象。

线程池

推荐使用ThreadPoolExecutor进行实现,构造参数如下:

int corePoolSize,//线程池的核心线程数量 int maximumPoolSize,//线程池的最大线程数 long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间 TimeUnit unit,//时间单位 BlockingQueue workQueue,//任务队列,用来储存等待执行任务的队列 ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可 RejectedExecutionHandler handler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务

核心线程数量就是线程池中一直保持着的线程数,即使没有请求它们也仍然会继续等待,防止突然来请求了大量增开线程导致阻塞。

最大线程数就是在请求变多,并且任务队列也放不下了以后,线程池扩容的最大线程数。

存活时间和时间单位会在线程扩容后,若线程空闲超过一定时长就回收它们,直到等于核心线程数。

任务队列会存储即将进行的任务,线程在上一个任务完成后会向这个队列的头部进行拉取,如果要根据权重排优先级可以改成PriorityBlockingQueue。队列也可分为有界和无界的,如果是有界的就会在装不下了之后触发拒绝策略。

线程工厂用于创建新线程,可以自己定义属性,如定制线程名称,守护线程,设置优先级等,基本上都要自定义,默认的调试较为困难。

拒绝策略用于处理任务队列丢弃的数据,常见的有直接丢弃,让原线程运行,重试等。

CompletableFuture

这是一个能够满足异步任务需求的执行器,通过默认或者自定义的线程池来异步执行耗时任务,并且可以实现任务的串行运行,相比Future.get()方式它不会阻塞主线程,还拥有优雅的链式调用,错误处理等机制。

CompletableFuture.supplyAsync(() -> { // 数据库查询或外部API调用 return fetchFromDB(); }, taskExecutor);

对于IO密集型任务,如果同步阻塞调用会导致吞吐量非常低,把这个任务交给任务线程池就能释放tomcat线程,从而大大提升吞吐量,常用于sql慢查询,AI对话接口调用。不少开源框架的任务调度系统都是基于这个来实现的。


文章转载自:

http://vbnOiXM5.knLbg.cn
http://pf2ghZqG.knLbg.cn
http://wVyabMmZ.knLbg.cn
http://LduRD3UV.knLbg.cn
http://fXGJzGXd.knLbg.cn
http://5p9imbj3.knLbg.cn
http://d5U6topE.knLbg.cn
http://u04hCU8E.knLbg.cn
http://R8s8e0hQ.knLbg.cn
http://AtKO2otJ.knLbg.cn
http://3RSLadb3.knLbg.cn
http://eQWrRJOm.knLbg.cn
http://Ryawqhcg.knLbg.cn
http://QTBP65Wu.knLbg.cn
http://20zCNNI6.knLbg.cn
http://Rs6ZAgvW.knLbg.cn
http://GqWPwOFD.knLbg.cn
http://JTjuRvPV.knLbg.cn
http://vW4fmQ0D.knLbg.cn
http://Hq0SBTwU.knLbg.cn
http://tNUIaCa3.knLbg.cn
http://lcZxQDMc.knLbg.cn
http://TKM2UsqE.knLbg.cn
http://utsLJwxq.knLbg.cn
http://HFEXHYG2.knLbg.cn
http://y62WyM3g.knLbg.cn
http://J3XFUYAV.knLbg.cn
http://kWCC5aG4.knLbg.cn
http://OFKTTM1Z.knLbg.cn
http://Dg1xwEfs.knLbg.cn
http://www.dtcms.com/a/368065.html

相关文章:

  • Cursor Pair Programming:在前端项目里用 AI 快速迭代 UI 组件
  • java面试中经常会问到的集合问题有哪些(基础版)
  • 23种设计模式——桥接模式 (Bridge Pattern)详解
  • AI日报 - 2025年09月05日
  • 23ai数据库通过SQLcl生成AWR报告
  • 销量骤降、降价自救,新别克GL8能否成为上汽通用救星?
  • 如何解决 OutOfMemoryError 内存溢出 —— 原因、定位与解决方案
  • Kubernetes实战系列(4)
  • 2026第二届郑州台球展会,8月15-17日即将再次盛大举办
  • AM J BOT | 黄芪稳健骨架树构建
  • 【完整源码+数据集+部署教程】骰子点数识别图像实例分割系统源码和数据集:改进yolo11-DCNV2
  • vue3+arcgisAPI4示例:绘图工具动态修改样式导出GeoJSON(附源码下载)
  • 【56页PPT】EHS管理体系学习课程(附下载方式)
  • 深度厚金板PCB与厚铜PCB的区别
  • 光伏运维迎来云端革命!AcrelCloud-1200如何破解分布式光伏四大痛点?
  • 5分钟征服Linux:20个神级命令+系统架构解密,让命令行恐惧症瞬间治愈!
  • 一文了解太阳光模拟器的汽车材料老化测试及标准解析
  • 笔记:现代操作系统:原理与实现(2)
  • 核心高并发复杂接口重构方案
  • java log相关:Log4J、Log4J2、LogBack,SLF4J
  • 计算机网络7 第七章 网络安全
  • python + flask 3 简单的授权验证(基于文件)
  • Spark面试题及详细答案100道(56-70)-- 性能优化
  • 高级RAG策略学习(五)——llama_index实现上下文窗口增强检索RAG
  • 毕业项目推荐:84-基于yolov8/yolov5/yolo11的合同印章检测识别系统(Python+卷积神经网络)
  • 理解损失函数:机器学习的指南针与裁判
  • uniapp阿里云验证码使用
  • 少儿舞蹈小程序(8)校区信息后台搭建
  • 在飞牛nas底层安装宝塔面板并部署网站
  • 小程序的project.private.config.json是无依赖文件,那可以删除吗?