第一章 并发编程的挑战

  1. 为什么要使用并发编程?
  • 主要是为了更有效地利用资源。即使是单核的CPU也可以多线程执行程序,多线程实际上是CPU分配时间片给各个线程,因为时间片非常短,所以看起来就像在同事执行,也更充分地压榨了CPU的性能。
  1. 使用并发编程的优缺点?
  • 优点:使用多线程能有效增加IO密集型程序的吞吐量,在一个线程等待IO的时候,多线程可以充分使用CPU性能创建更多的线程执行其他任务,避免CPU空闲,更有效地压榨CPU资源
  • 缺点:并发编程不能无脑使用,如计算密集型程序每个线程都对CPU有很大负担,就算使用多线程能压榨的CPU算力也很有限。同时大量使用线程,就不可避免线程上下文切换问题,有时候大量的线程上下文切换反而影响了系统响应时间。使用并发编程还存在死锁的风险。

参考书中查看线程上下文切换次数的命令

//使用jstack命令dump线程信息
sudo -u admin /opt/ifeve/java/bin/jstack 31177 > /home/dump31177
//统计所有线程分别处于什么状态
grep java.lang.Thread.State dump31177 | awk '{print $2$3$4$5}' | sort | uniq -c

3.什么是死锁?如何避免?

  • 两个使用锁的线程同时需要获取对方的锁就会出现死锁的问题
  • 有几个避免死锁的常见方法:
    1. 避免一个线程同时获取多个锁
    2. 避免一个线程在锁内占用多个资源,尽量保证每个锁只占用一个资源
    3. 使用Lock.tryLock(timeout)来替代使用内部锁级制
    4. 对于数据锁,加锁和解锁必须在一个数据库连接里

第二章 Java并发机制的底层实现原理

java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终转换成汇编指令在CPU上执行。并发机制的实现依赖于虚拟机的实现和CPU指令。

  1. volatile是做什么的?他的实现原理?应用场景?
  • volatile是轻量的synchronized,在多处理器开发中保证了共享变量的“可见性”。即在一个线程修改一个共享变量时,另一个线程能看见这个变量修改后的值。如果使用恰当的话他比synchronized开销更小,因为他不会引起线程上下文切换和调度
  • volatile在实现时使用了操作系统的LOCK指令这个指令主要实做了两步操作
    1. 将缓存行的内容写回到内存即缓存锁定
    2. 将缓存了该内存地址信息的缓存失效
  • 应用场景可以在使用共享变量时利用系统操作指令保证缓存行数据一致性
  1. synchronized是如何使用的?是干什么用的?
  • JVM一个线程执行到synchronized锁的代码行时,会从他锁住的对象获取锁。当其他线程运行到同一行时,若不能获取锁时线程将被阻塞,一个对象的锁只能被一个线程获取。synchronized在JAVA中有三种使用场景:

    1. 在方法上使用时锁住的是具体对象
    2. 在静态方法上使用时锁住的是class对象
    3. 同步方法块锁住的是括号内的对象
      他的使用场景主要是为了避免多线程并发使用共享对象进行非原子操作时产生的并发问题,例如经典的i++问题,线程1和线程2同时运行到i++,同时从内存中获取到i的值为1,最后i的值为2但实际上i++运行了两次。在业务上就有可能造成商品超卖登问题。
  1. synchronized实现原理是什么?
  • JAVA中的synchronized使用了monitorenter实现,代码编译之后在同步代码块开始时会插入monitorenter,结束时插入monitorexit。保证每一个monitorenter都有一个monitorexit对应,每个对象都有一个monitor对象与之关联,当对象的monitor被持有后他将处于锁定状态。线程执行到monitorenter时线程会尝试获取monitor所有权即尝试获取对象的锁
  1. java对象头存放了哪些锁相关的信息?
  • 对象头存储了:

    1. 存放对象HashCode或所信息的MarkWord
    2. 存放类型数据的指针Class Metadata Address
    3. 数组对象长度(对象是数组时存在)
  • 其中对象的锁相关信息存在了MarkWord中,MarkWord主要存放了,锁状态、对象的HashCode、分代年龄、是否偏向锁、锁标志位。其中的数据会根据锁标志位的变换而变换
  1. 他的锁升级过程是怎样的?什么是锁升级?
  • 锁有四种状态:无状态锁,偏向锁,轻量级锁,重量级锁。级别从低到高,随着锁竞争情况逐渐升级即使锁升级。但是锁的升级之后不能降级,目的是为了提升获取锁和释放锁的效率
  1. 什么是偏向锁?
  • 在大多数情况下,一个锁常由同一个线程获得,因此引入了偏向锁的概念。当一个线程访问锁时会在锁对象的对象头储存偏向线程的ID,以后该线程进入锁不需要进行CAS操作来加锁和解锁。只需要简单的测试一下对线头的MarkWord里是否存储了指向当前线程的偏向锁。如果测试成功,标识线程已经获得锁。如果测试失败则使用CAS获取锁,获取锁成功之后再将MarkWord里的偏向锁标记指向当前线程。
  1. 偏向锁的撤销逻辑?
  • 偏向锁只有在其他线程竞争时才会释放锁。撤销锁时会先暂停拥有偏向锁的线程并判断他是否活着,如果线程不处于活动状态会先将对象设置成无锁状态。如果线程仍然活着,拥有偏向锁的栈会被执行,遍历对象的锁记录,栈中的锁记录和对象头的Mark Word要么重新偏向于其他线程,要么恢复到无锁或者标记对象不适合作为偏向锁,最后唤醒暂停线程。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dNNLd4mj-1651226209900)(FBF16BFF297F417A9EEBD16DCC93D6DF)]
  1. 他是如何实现轻量锁和偏向锁的?
  • 偏向锁是在加锁的对象头里保存了线程ID,在获取锁时会去比对线程的ID如果能匹配则不用CAS去获取锁和解锁,标识线程已经获取到锁。如果不能匹配则CAS获取锁
  • 轻量级锁加锁线程在执行前JVM会先在当前线程的栈帧中创建用于存储锁记录的空间,并将对象头中的Mark Word拷贝到所记录中(Displaced Mark Word)然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针,如果成功则线程获取到锁。如果失败则表示存在锁竞争,当前线程使用自旋来获取锁。轻量级锁解锁时,会将所记录中的Mark Word替换回对象头。如果成功表明没有竞争发生,如果失败则表示存在竞争锁膨胀为重量锁。
  1. 为什么要使用轻量锁
  • 竞争线程若获取不到锁,会不断自旋获取锁,并不会阻塞。但长时间获取不到锁轻量级锁会膨胀成为重量锁
  • 锁的优缺点对比
优点 缺点 适用场景
偏向锁 加锁和解锁不需要额外的消耗,和执行非同步方法相比仅存在纳秒级的差距 如果线程间存在锁竞争,会带来额外的锁撤销消耗 适用于只有一个线程访问同步块的场景
轻量级锁 竞争的线程不会阻塞,提高了程序的响应速度 如果始终得不到锁竞争的线程会自选消耗CPU 追求响应时间同步块执行速度非常快
重量级锁 线程竞争不使用自旋,不会消耗CPU 线程阻塞,响应时间缓慢 追求吞吐量同步块执行速度较长
  1. 什么是原子操作?
  • 指不能被中断的一个或一系列操作
  1. 什么是CAS,缓存行,CPU流水线,内存顺序冲突
术语名称 英文 解释
缓存行 Cache line 缓存的最小操作单位
比较并交换 Compare and Swap CAS操作需要输入的两个数值,一个旧值和一个新值,在操作期间先比较旧值有没有发生变化,如果没有发生变化,才交换成新值,发生了变化则不交换
CPU流水线 CPU pipeline CPU流水线的工作方式就像工业生产上的装配流水线,在CPU中由56个不同功能的电路单元组成一条指令处理流水线,然后将一条X86指令分成56步后再由这些电路单元分别执行,这样就能实现在一个CPU时钟周期内完成一条指令,因此提高CPU运算速度
内存顺序冲突 Memory order violation 内存顺序冲突一般是由假共享引起的,假共享指多个CPU同时修改一个缓存行的不同部分
  1. CPU如何实现原子操作?
  • 使用总线锁保证原子性
  • 使用缓存锁保证原子性
  1. 什么i++问题
  • 在多个CPU操作共享变量时,同时从各自的缓存中读取变量i,分别进行+1操作后协会系统内存中。
  1. JAVA如何实现原子操作
  • 主要依赖实现了原子操作的Atomic相关的类,其中的CAS操作正是利用了处理其提供的COMPXCHG指令。

JAVA并发编程艺术读书笔记(1,2章节)相关推荐

  1. Java并发编程艺术----读书笔记(二)

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a724888/article/details/64214595  java并发编程艺术2 jav ...

  2. Java 并发编程艺术 读书笔记

    第 1 章 并发编程的挑战 1.1.3 如何减少上下文切换 减少上下文切换的方法有无锁并发编程.CAS 算法.使用最少线程和使用协程. 无锁并发编程.多线程竞争锁时,会引起上下文切换,所以多线程处理数 ...

  3. Java并发编程艺术读书笔记

    1.多线程在CPU切换过程中,由于需要保存线程之前状态和加载新线程状态,成为上下文切换,上下文切换会造成消耗系统内存.所以,可合理控制线程数量. 如何控制: (1)使用ps -ef|grep appn ...

  4. Java并发编程艺术阅读笔记(一)

    Java并发编程艺术阅读笔记(一) 1.什么是上下文切换 CPU通过时间片分配算法循环执行任务,执行完一个任务的时间片后就会切换到下一个任务.但是在切换任务之前会保存上一个任务的状态,在切换回该任务, ...

  5. Java并发编程艺术学习笔记(五)

    Java并发编程艺术学习笔记(五) Java并发容器和框架 Java为开发者也提供了许多开发容器和框架,可以从每节的原理分析来学习其中精妙的并发程序. 一.ConcurrentHashMap的实现原理 ...

  6. java并发编程实践 读书笔记_Java - 并发编程实践(读书笔记)

    [注] 同步机制保证:1)原子性 2)内存可见性: Volatile变量只能保证:1)可见性: - 恰当的同步,同步的弱形式,确保对一个变量的更新以可预见的方式告知其他线程. [注] 用锁来协调访问变 ...

  7. Java并发编程实战读书笔记

    Java并发编程 标签(空格分隔): 并发 多线程 基础 线程 在执行过程中,能够执行程序代码的一个执行单元,在Java语言中,线程有四种状态:运行,就绪,挂起,结束. 并发特性 原子性 一个操作不会 ...

  8. Java并发编程实战读书笔记三

    第七章 取消和关闭 Java没有提供任何机制来安全的终止线程,虽然 Thread.stop 和 suspend 等方法提供了这样的机制,但由于存在着一些严重的陷,因此应该避免使用 7.1任务取消 7. ...

  9. Java并发编程实战读书笔记(一)——线程安全性、对象共享

    一.线程安全性 一个对象是否需要是线程安全的,取决于它是否被多个线程访问. 当多个线程访问,并且其中有一个执行写入时,必须采用同步机制,Java中主要的同步关键字是 synchronized 独占加锁 ...

最新文章

  1. bootstraptable 汇总_JS组件系列——表格组件神器:bootstrap table
  2. 浅谈常用的Web安全技术手段
  3. com.esri.android,解决ArcGIS Android Could not find class 'com.esri.android.map.MapView'问题
  4. java js跳出循环_[Java教程]js循环的总结
  5. 蚂蚁资深算法专家周俊:从原理到落地,支付宝如何打造保护隐私的共享智能?...
  6. 95-31-020-ChannelGroup-DefaultChannelGroup
  7. 怎么调节Ubuntu系统的屏幕亮度
  8. android studio 登录与注册,Android Studio登录/注册系统构想
  9. office2016风格后台管理系统html模板下载-uimaker设计
  10. 永恒之塔4.0单机MYSQL,永恒之塔数据库
  11. broker可以禁用吗 time_【pximouse可以禁用吗】pximouse是什么程序_pximouse是什么
  12. java中cookie的有效时间设置
  13. 《沙漠自然教育项目全纪实》发布 圣牧有机让绿色的种子种进更多孩子心里
  14. 4个字母的排列组合c语言,1,2,3,4四个数字有多少种排列组合,是怎样的
  15. .net core 中使用confluent kafka构建生产者
  16. 沙扬娜拉--靠!今天怎么了,成了诗人?!
  17. WIN7 32位 安装RVDS3.1 问题
  18. STM32Cube学习笔记-SPI通讯
  19. 基于SSM的在线拍卖平台(二手物品拍卖平台Java+MySQL+SSM)
  20. 怎么把视频导出为GIF?一分钟教你视频转gif在线转换

热门文章

  1. 如何恢复已清空的 Windows 回收站?
  2. 精品课 - Python 数据分析
  3. python实现内容推荐_Python实现个性化推荐一
  4. 吸金树脂A-21S吸附贵金属的性能解析
  5. 【ALB 】ALB文档阅读
  6. STM32H750_QSPI_W25QXX_XIP
  7. python 实现 webp 图片转 jpg
  8. 【如何防御黑客对window XP系统的入侵】
  9. vs2010安装包制作
  10. 关于视觉重定位(VPS)的工作经验分享