Java并发(多线程和锁机制)

2023-11-18

part 01:Java线程

1、进程和线程的区别:

  • 进程是操作系统进行资源分配的最小单位,线程是操作系统进行任务分配的最小单位,一个进程可以有多个线程。

2、Java开启线程的方式:

  • 继承Tread类,重写run方法;
  • 实现Runnable接口,实现run方法;
  • 实现Callable接口,实现call方法;(FutureTask创建线程,获取线程返回值);
  • 通过线程池开启线程(优点:提升线程池中线程的使用率,减少线程的创建、销毁所花的时间以及系统资源的开销;线程池可以控制线程数,有效提升服务器的使用资源)

3、四种常用的线程池:

  • newCachedThreadPool:可缓存线程池,灵活回收空闲线程,若无可回收,则新建线程。没有核心线程,线程数量没有上线,默认消亡时间为60秒,阻塞队列是SynchronousQueue,没有存储性质的阻塞队列,取值操作和放入操作必须是互斥的,可以理解为每当有任务放入时立即有线程将它取出执行。
  • 优点:提高了线程的复用率,当第二个任务开始,第一个任务已经结束,那么第二个任务会服用第一个任务创建的线程,并不会重新创建新的线程。
  • 缺点:无法控制最多需要多少个线程同时处理,它会自动扩展线程数
                    
  • newFixedThreadPool:固定核心线程数线程池,可以控制线程的最大并发数量,使服务器达到最大的使用率,同时又可以保证流量突然增大也不会占用服务器过多的资源。
  • 缺点:核心线程数量就是最大线程数量,所以线程池内的线程永远不会销毁,采用无参数的链表阻塞队列,存在任务积压导致内存溢出的风险。
                  
  • newScheduledThreadPool:固定调度线程池。有固定的核心线程,线程的数量没有限制,支持定时以及周期性任务执行,可以延迟任务的执行时间,也可以设置一个周期性的时间让任务重复执行。两种延迟方法:
  • scheduleAtFixedRate:当前任务时间小于间隔时间,每次到点即执行;当前任务执行时间大于等于间隔时间,任务执行后立即执行下一次任务,相当于连续执行。
  • scheduledWithFixedDelay:每当上次任务执行完毕后,每隔一段时间执行。(可以做每天几点执行任务)
                 
  • newSingleThreadExecutor:单线程线程池,由始至终都由一个线程来执行。所有任务按照FIFO指定顺序执行
                  
4、线程池参数:
  • corePoolSize:核心线程数;
在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
一般需要根据任务的类型来配置线程池大小:
  如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 NCPU+1
  如果是IO密集型任务,参考值可以设置为2*NCPU
  • maximumPoolSize:最大线程数,核心线程+线程队列;最大线程数 =(最大任务数-队列容量)/每个线程每秒处理能力
  • keepAliveTime:最大空闲时间,超过空闲时间不工作的线程会被销毁,默认用于非核心线程,通过设置 allowCoreThreadTimeOut(true)后,也会用于核心线程
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
  • unit:最大空闲时间时间单位
TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒
  • workQueue:等待执行的任务队列,如果核心线程没有空闲的,新来的任务会被放到这个等待队列中
    • SynchronousQueue:将任务直接交给线程而不保持它们。如果不存在可用于立即运行任务的线程,则试图将任务加入队列失败,会构造一个新的线程。要求maximumPoolSize,以避免拒绝新提交的任务。
    • 无界队列:LinkedBlockingQueue,所有corePoolSize线程都在忙时新任务在队列中等待。适用场景:所有任务互不影响,用于处理瞬态突发请求。
    • 有界队列:ArrayBlockingQueue,有助于防止资源耗尽,但是可能较难调整和控制。当ArrayBlockingQueue满时,则又会开启新的线程去执行,直到线程数量达到maximumPoolSize。
    • 延时队列:DelayedWorkQueue,保证添加到队列中的任务,会按照任务的延时排序,延时时间少的任务首先被获取
  • threadFactory:用于实现生成线程的方式,定义线程名格式,是否后台执行等等
    • Spring框架提供的:CustomizableThreadFactory
ThreadFactory springThreadFactory = new CustomizableThreadFactory("springThread-pool-");
  • Google guava工具类提供的:ThreadFactoryBuilder
  • Apache commons-lang3 提供的:BasicThreadFactory
ThreadFactory basicThreadFactory = new BasicThreadFactory.Builder()
          .namingPattern("basicThreadFactory-").build();
  • handler:当线程数达到最大线程数maximumPoolSize,再有新的任务到达时启动的策略。
    • ThreadPoolExecutor.AbortPolicy:直接抛出异常(默认)
    • ThreadPoolExecutor.DiscardPolicy:直接丢弃任务,但不抛出异常
    • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后将新加入的任务加入等待队列
    • ThreadPoolExecutor.CallerRunsPolicy:由线程池所在的线程处理该任务
5、线程工具类:
  • CountDownLatch:栅栏,一般用于某个线程等待若干个其他线程执行完任务之后,他才执行,不可重用
  • CylicBarrier:  回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行,一组线程互相等待至某个状态,然后这一组线程再同时执行,可重用
  • Semaphore:信号量

part 02:Java锁

1、synchronized和reentrantLock的区别:

  • synchronized 不需要用户去手动释放锁,synchronized 代码执行完后系统会自动让线程释放对锁的占用; ReentrantLock则需要用户去手动释放锁,如果没有手动释放锁,就可能导致死锁现象。
  • Lock等待可中断,而synchronized只会让等待的线程一直等待下去。如果线程A正在执行锁中代码,线程B正在等待获取该锁。时间太长,线程B不想等了,可以让它中断自己。
  • synchronized是非公平锁,reentrantLock可以设置是否为公平锁,通过构造方法new ReentrantLock时传入值进行选择,true为公平锁,false为非公平锁
  • 一个ReentrantLock可以绑定多个Condition对象,结合await()/singal()方法实现线程的精确唤醒,而synchronized通过Object类的wait()/notify()/notifyAll()方法要么随机幻想一个线程要么唤醒全部线程
  • synchronzied锁的是对象,锁是保存在对象头里面的,根据对象头数据来标识是否有线程获得锁/争抢锁;ReentrantLock锁的是线程,根据进入的线程和int类型的state标识锁的获得/争抢。
  • 通过Lock可以知道有没有成功获取到锁
大量线程同时竞争,ReentrantLock要远胜于synchronized。
JDK5中,synchronized是性能低效的,因为这是一个重量级操作,对性能的最大影响是阻塞的实现,挂起线程和恢复线程的操作,都需要转入内核态中完成,给并发带来了很大压力。
JDK6中synchronized加入了自适应自旋、锁消除、锁粗化、轻量级锁、偏向锁等一系列优化,官方也支持synchronized,提倡在synchronized能实现需求的前提下,优先考虑synchronized来进行同步。
2、锁升级过程:
  • 偏向锁:一个线程多次获得同一个锁,不存在锁竞争。
当线程1访问代码块并获取锁对象时,会在java对象头和栈帧中记录偏向的锁的threadID,因为偏向锁不会主动释放锁,因此以后线程1再次获取锁的时候,需要比较当前线程的threadID和Java对象头中的threadID是否一致,如果一致(还是线程1获取锁对象),则无需使用CAS来加锁、解锁;如果不一致(其他线程,如线程2要竞争锁对象,而偏向锁不会主动释放因此还是存储的线程1的threadID),那么需要查看Java对象头中记录的线程1是否存活,如果没有存活,那么锁对象被重置为无锁状态,其它线程(线程2)可以竞争将其设置为偏向锁;如果存活,那么立刻查找该线程(线程1)的栈帧信息,如果还是需要继续持有这个锁对象,那么暂停当前线程1,撤销偏向锁,升级为轻量级锁,如果线程1 不再使用该锁对象,那么将锁对象状态设为无锁状态,重新偏向新的线程。(先看对象头中的threadID是否一致,不一致看持有锁的对象是否存活,存活看是否还持有锁,还持有锁就升级为轻量级锁
  • 轻量级锁:竞争锁对象的线程不多,而且线程持有锁的时间不长的情景,其他线程自旋等待锁。
线程1获取轻量级锁时会先把锁对象的对象头MarkWord复制一份到线程1的栈帧中创建的用于存储锁记录的空间(称为DisplacedMarkWord),然后使用CAS把对象头中的内容替换为线程1存储的锁记录(DisplacedMarkWord)的地址;
如果在线程1复制对象头的同时(在线程1CAS之前),线程2也准备获取锁,复制了对象头到线程2的锁记录空间中,但是在线程2CAS的时候,发现线程1已经把对象头换了,线程2的CAS失败,那么线程2就尝试使用自旋锁来等待线程1释放锁。 自旋锁简单来说就是让线程2在循环中不断CAS
但是如果自旋的时间太长也不行,因为自旋是要消耗CPU的,因此自旋的次数是有限制的,比如10次或者100次,如果自旋次数到了线程1还没有释放锁,或者线程1还在执行,线程2还在自旋等待,这时又有一个线程3过来竞争这个锁对象,那么这个时候轻量级锁就会膨胀为重量级锁。重量级锁把除了拥有锁的线程都阻塞,防止CPU空转。
  • 重量级锁:很多线程竞争锁,且锁持有时间长。
3、threadlocal
  • threadlocal主要作用是做数据隔离,填充的数据只属于当前线程,防止当前线程的变量被其他线程篡改
  • Spring采用threadlocal的方式,来保证单个线程中的数据库操作使用的是同一个数据库连接,实现事务隔离级别(threadlocal+AOP实现)
  • 每个Thread都维护了自己的threadLocals变量
  • 使用InheritableThreadLocal可以实现多个线程访问ThreadLocal的值
  • ThreadLocal的key被设计成weakReference弱引用,在没有被外部强引用时,发生GC会被回收, 如果创建ThreadLocal的线程一直持续运行,那么这个Entry对象中的value就有可能一直得不到回收,发生内存泄露。怎么解决:在使用的最后remove把值清空
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java并发(多线程和锁机制) 的相关文章

  • 在 Java 中重置 Graphics2D 对象

    我正在用 Java 尝试 Graphics2D 但像往常一样 我被困住了 P 问题是 假设我有这个代码 Graphics2D g Graphics2D this getGraphics Inside a JFrame g rotate Ma
  • 面试问题 - 在排序数组 X 中搜索索引 i,使得 X[i] = i

    昨天面试时 我被问到了以下问题 考虑一个 Java 或 C 数组X它已排序并且其中没有两个元素是相同的 如何最好地找到索引i这样该索引处的元素也是i 那是X i i 作为澄清 她还给了我一个例子 Array X 3 1 0 3 5 7 in
  • mvn dependency:analyze 结果不正确

    我一直在寻找一种工具 它能够向您显示未使用的依赖项 我很快就偶然发现了 Maven 命令mvn dependency analyze 这样做的问题是 它经常检测到 未使用的 依赖项 如果缺失 这些依赖项就会导致构建失败 这是优化项目的示例
  • 使用 ScheduledExecutorService 安排每月任务

    我想在该月的某一天的特定时间安排一项任务 每次运行之间的间隔可以设置在 1 到 12 个月之间 在java中 可以使用ScheduledExecutorService以固定的时间间隔调度任务 既然一个月的天数不固定 那么如何实现呢 提前致谢
  • lombok - 多个镜头中的 @Builder 模式

    I use Builder of 龙目岛项目 https github com rzwitserloot lombok 所以考虑我有这个例子 Builder public class Client private Getter Setter
  • Android - Java - 发送 facebook 聊天消息的意图(facebook 禁用 xmpp)

    Facebook 已弃用 xmpp API 有没有办法打开意图 或将数据传递到fb 以在Android设备上发送聊天消息 设备上安装的 Facebook 和 Messenger 应用 谢谢 您需要将 uri 传递给意图 这里10000572
  • 如何用java对jpg进行像素化?

    我正在尝试使用 Java 6 对 JPEG 进行像素化 但运气不佳 它需要使用 Java 而不是像 Photoshop 这样的图像处理程序 并且它需要看起来像老派 像这样 有谁能够帮助我 使用java awt image javadoc h
  • WSDL 表示中的枚举类型

    WSDL 表示如下
  • 让 Java 与 Windows 10 Ubuntu 一起使用

    我安装了 Windows 10 周年更新 以便可以在 Windows 上的 Ubuntu 上尝试 Bash 看如何安装 http www howtogeek com 249966 how to install and use the lin
  • 序言中不允许引用

    请帮我找到这个异常的原因 我使用以下罐子 core renderer jar itext paulo 155 jar 第一个文档 xhtml lt xml version 1 0 encoding UTF 8 gt lt DOCTYPE h
  • 如何在最短的时间内克隆java中的输入流

    有人可以告诉我如何克隆输入流 并花费尽可能少的创建时间吗 我需要多次克隆输入流以使用多种方法来处理 IS 我尝试了三种方法 但由于这样或那样的原因 事情不起作用 方法 1 感谢 stackoverflow 社区 我发现以下链接很有帮助 并将
  • SOAP Web 服务中的用户身份验证

    我提出了一个关于JAX WS 身份验证和授权 如何 https stackoverflow com questions 5314782 jax ws authentication and authorization how to 讨论了安全
  • 如何在 Eclipse 中使用 Hibernate Tools 生成 DAO?

    我在用着 Eclipse Java EE IDE Web 开发人员 版本 Indigo 发布 使用 hibernate 工具 我对 Eclipse 中的 hibernate 很陌生 所以我学习如何配置 hibernate 并使用注释生成 P
  • Java 中 LINQ 的等价物是什么? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 Java 中 LINQ 的等价物是什么 没有什么比 LINQ for Java 更好的了 Edit 现在
  • 在Java中一个接一个地播放WAV文件

    我正在尝试玩几个WAV http en wikipedia org wiki WAV文件一个接一个 我尝试了这个方法 for String file audioFiles new AePlayWave file start 但这会同时播放它
  • ObservableList 不更新 ArrayList

    对于学校作业 我们正在使用 JavaFX 中的 ObservableList 对象 对吗 我已经为此工作了一天多了 但无法弄清楚 老师只告诉我们 谷歌一下 所以这也没有帮助 基本上 我们正在开发一个基本的管理应用程序来跟踪人们及其家人 人们
  • 对于每个抛出异常的语句,try/catch 是否被视为反模式?

    我目前正在审查同事的 Java 代码 我看到很多情况下 每个可能抛出异常的语句都被封装在自己的 try catch 中 其中 catch 块都执行相同的操作 哪个操作与我的问题无关 对我来说 这似乎是一种代码味道 我记得读到过它是一种常见的
  • Android:如何以编程方式仅圆化位图的顶角?

    我目前正在使用这段代码 Override public Bitmap transform Bitmap source Bitmap result Bitmap createBitmap source getWidth source getH
  • 何时以及为何使用缓冲输入和输出流? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我读到这些是为了减少磁盘 网络调用开销而使用的 这在写操作的情况下似乎很好 但是进行缓冲读取有什么好处呢 如果您按字节读取文件 则每次都会进
  • 用于将字符串与通配符模式进行匹配的递归函数

    所以我一整天都在试图解决这个作业 只是无法完成 以下函数接受 2 个字符串 第二个 不是第一个 可能包含 的 星号 An 是字符串的替换 空 1个字符或更多 它可以出现 仅在s2中 一次 两次 更多或根本不出现 它不能与另一个相邻 ab c

随机推荐

  • Android-CMakeLists.txt 链接第三方库(动态或者静态库)到自己的生成库中

    最近在做关于NDK开发的项目 编译方式通过cmake 如何将第三方动态链接库连接到自己生成的动态库中 按照以下步骤 1 首先看目录结构 首先将第三方库复制到jniLibs下 并创建对应的CUP平台目录 2 CMakeLists txt 方式
  • [转载]稳健语音特征和音频场景识别方法研究

    音频应用相关 http max book118 com html 2014 0508 8133338 shtm
  • 斯坦福大学自然语言处理第三课“最小编辑距离(Minimum Edit Distance)”

    一 课程介绍 斯坦福大学于2012年3月在Coursera启动了在线自然语言处理课程 由NLP领域大牛Dan Jurafsky 和 Chirs Manning教授授课 https class coursera org nlp 以下是本课程的
  • vim:批量化注释及删除注释

    1 批量化注释 首先按Esc进入到命令模式 注意左下角变为NORMAL 按住 Ctrl v 进入到视图模式 注意左下角变为 V BLOCK 再通过 h 左 j 下 k 上 l 右 选中区域 ps 按住 shift g 即可选中当前行及其下所
  • 随笔之---maven的知识

    1 maven metadata xml 这个文件是干嘛的 2 setting 中 是啥 表示所有依赖仓库的获取 走 这里 例如 任何仓库的请求 都被转到 下面的地址 如果 不是 是central则关于 中央仓库的请求会转到 下面的地址
  • 【服务器磁盘挂载步骤】

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 服务器磁盘挂载步骤 一 步骤 一 步骤 做了三块盘 2个raid0 一个raid5 具体步骤如下 1 查看下磁盘信息的两种方法 lsblk fdisk l 2 磁盘分区 su
  • 【Qt】QSlider样式定制

    一 背景 QSlider空间是Qt官方的控制控件 在项目开发中 很多地方都会使用到这个控件作为滑动块 我们可以使用样式表来定制QSlider的显示样式 从而满足多种开发需求 一个QSlider包括以下三个部分 1 滑动过的槽 2 滑块 3
  • 阶段性目标规划

    1 2022 2023的目标 1 1 考证 1 软考 嵌入式系统工程师中级 2 架构师设计 1 2 研究产出 时间节点 2021 11 论文的修改与实验 操作系统 2021 12 Emd 与TQWT 算法的 选题与研究 与实验论文撰写 1
  • 安装git,解决"git 不是内部或外部命令,也不是可运行的程序"问题

    若是为解决 git 不是内部或外部命令 也不是可运行的程序 问题 在文末 点击此处 可快速到达 官网链接 https git scm com download win Tips 官网下载的速度忒慢 我是右键复制了链接地址 然后好在迅雷上下载
  • md5加密小工具制作(js版)

    废话不多说 上图上代码 注 该demo样式采用bootstrap框架的css样式做的 页面布局代码
  • linux程序下C语言代写,代写C语言 代做C程序 C++ assembler(QQ:2365427650&http://www.daixiec.com/)...

    The aim of this assignment is to write a two pass assembler for an extended SIMPLE instruction set Then write and test p
  • Unity协程和线程的区别

    先简要说下结论 协同程序 coroutine 与多线程情况下的线程比较类似 有自己的堆栈 自己的局部变量 有自己的指令指针 IP instruction pointer 但与其它协同程序共享全局变量等很多信息 协程 协同程序 同一时间只能执
  • YOLOv3使用笔记——Kmeans聚类计算anchor boxes

    anchor boxes用来预测bounding box faster rcnn中用128 128 256 256 512 512 分三个尺度变换1 1 1 2 2 1 共计9个anchor来预测框 每个anchor预测2000个框左右 使
  • 磁盘性能测试工具DiskSpd

    一 DiskSpd工具介绍 https github com microsoft diskspd releases 工具下载 https github com Microsoft diskspd 源码 https github com Mi
  • 保存原始rgb8bit 数据到bmp文件

    就填充方式来说 跟24位位图基本是一样的 不同的是bitcolor 位设置的颜色位数要填充为8 而不是24 百度了很久 目前只能是勉强能保存成图片 能正常打开 但目前还有未能理解的问题 列举如下 如果有知道的朋友 希望能得到您的慷慨解惑 感
  • 高版本Andriod Studio集成HMS环境看这篇就够了(附加步骤多图、资源下载、源代码、问题总结)

    Aandriod Studio集成HMS环境 0 前言 1 开发环境介绍 a Java版本 b Android Studio版本 c Gradle SDK版本 2 注册认证华为开发者联盟 个人开发者 a 进入网址 点击右上角管理中心 b 注
  • 软件测试—第六章白盒测试基本路径测试法

    一 基本路径法 1 为什么使用基本路径法 一是降低了测试用例设计的难度 只要搞清了各种流程 就可以设计出高质量的测试用例来 而不用太多测试方面的经验 二是在测试时间较紧的情况下 可以有的放矢的选择测试用例 而不用完全根据经验来取舍 2 什么
  • 如何设置当我们点击鼠标右键时,可以有新建Typora的选项

    最近研究了一下注册表 感觉这个东西还是挺有意思的 今天周末放假 打算写一点日记 当然是不发表的那种 然后我果断打开了Typora 不过由于好久没用Typora了 我忘记把他放在哪里了 找了一段时间终于找到了 我突然想到 为什么不把Typor
  • 目标检测算法之YOLOV3

    本博客中YOLO系列均为个人理解笔记 欢迎评论指出理解有误或者要讨论的地方 YOLOV3模型相比于v2来说 实质性的改进并不大 更多的是一些技术的堆叠 其并不像yolov2对于v1一样 由巨大的改变和提升 其相对于yolov2 改变在于 1
  • Java并发(多线程和锁机制)

    part 01 Java线程 1 进程和线程的区别 进程是操作系统进行资源分配的最小单位 线程是操作系统进行任务分配的最小单位 一个进程可以有多个线程 2 Java开启线程的方式 继承Tread类 重写run方法 实现Runnable接口