Jave并发的艺术


并发编程的挑战

上下文切换

CPU通过时间片分配算法来循环执行任务,当前时间片执行完之后会切换到下一个任务。但是,切换会保存上一个任务的状态,一遍下次切换回这个任务时,可以再次加载这个状态。所以任务从保存到再加载的过程就是一次上下文切换。

如何减少上下文切换

减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程

  • 无锁并发编程:多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法避免使用锁,如将数据ID按照Hash算法取模分段,不同的线程处理不同段的数据
  • CAS算法:Java的Atomic包使用CAS算法来更新数据,而不需要加锁
  • 使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态
  • 协程:在单线程实现多任务的调度,并在单线程里维持多个任务间的切换

死锁

死锁常见的原因是,线程之间相互等待。避免死锁的几个常见方法:

  • 避免一个线程获取多个锁
  • 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
  • 尝试使用定时锁,使用lock.tryLock(timeout)来代替使用内部锁机制
  • 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况

底层实现原理

volatile

volatile的定义与实现原理

Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获取这个变量。所以java提供了volatile,在某些情况下面比锁更加的方便。如果一个字段被声明为volatile,Java线程内存模型确保所有线程看到这个变量的值是一致的。

volatile如何保证可见性:通过Lock前缀指令,对volatile进行写时,JVM会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存

  • Lock前缀指令会引起处理器缓存行写回到内存
  • 一个处理器的缓存回写会导致其他处理器的缓存无效

synchronized

synchronized的介绍

并发编程里面元老级别的存在,重量级的锁。Java里面每一个对象都可以作为锁

  • 对于普通的方法,锁是当前实例的对象
  • 对于静态同步方法,锁是当前类的Class对象
  • 对于同步方法块,锁是Synchronized括号里配置的对象

Java对象头

synchronized用的锁是存在Java对象头里面的。对象头的内容

  • Mark Word:存储对象的HashCode或锁信息
  • Class Metadata Address:储存到对象类型数据的指针
  • Array length:数组的长度

Mark Word里默认存储对象的HashCode、分代年龄和锁标记,Mark Word里储存的数据会随着锁标志位的变化而变化。以下是四种状态的变化

  • 轻量级锁:指向栈中锁记录的指针,锁标志位 00
  • 重量级锁:指向互斥量(重量级锁)的指针 ,锁标志位 10
  • GC标记:空,锁标志位 11
  • 偏向锁:线程ID,Epoch,对象分代年龄,是否是偏向锁,锁标志位 01

锁的升级与对比

锁一共有四种状态,级别从低到高依次是:无锁状态、偏向锁状态,轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。注意:锁可以升级但是不能够降级。一些的设计目的只有一个。为了提高获得锁和释放锁的效率

  • 偏向锁:大多数情况下,锁不仅不存在多线程竞争,而且总是由他同一个线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。如:当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程再次进入和退出同步块时不需要进行CAS操作来加锁和解锁,仅仅判断一下对象头里面的Mark Word里面是否存储着指向当前线程的偏向锁。如果有,表示当前线程已经获得了锁;如果没有,则使用CAS竞争锁,再尝试使用CAS将对象头的偏向锁指向当前线程
  • 轻量级锁:线程在执行同步块之前,JVM会先在当前线程的栈帧中创建用于储存记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程就会获得锁,如果失败,表示其他线程竞争锁,当前线程便可以尝试通过自旋来获取锁,自旋失败之后,锁就会膨胀成重量级锁
  • 重量级锁:因为自旋会消耗CPU,为了避免无用的自旋(如:获得锁的线程被阻塞住了),一旦锁升级为重量级锁就不会恢复到轻量级锁状态。当锁出于这个状态下,其他线程试图获取锁时,都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进入新一轮的夺锁之争

原子操作的实现原理

原子(atomic),不能被进一步分割的最小粒子,原子操作:不能被中断的一个或一系列的操作。

处理器如何实现原子操作

  • 第一个机制,通过总线锁来保证原子性
  • 第二个机制,通过缓存锁定来保证原子性

Java如何实现原子操作

可以通过锁,和循环CAS的方式实现原子操作

CAS

CAS(Compare And Swap):比较并且交换。一个旧值,一个新值,操作之前比较旧值有没有发生变化,如果没有发生变化,才换成新值,发生了变化则不交换

CAS存在的三大问题:

  • ABA问题:CAS操作需要在操作的值的时候,检查值有没有发生变化。但是如果一个值原来是A,变成了B,又变成了A,使用CAS进行检查时会发现他的值没有发生变化,但是实际上他发生了变化。解决方案:给变量加上版本号
  • 循环时间长开销大:自旋CAS如果不成功,会给CPU带来非常大的开销
  • 只能保证一个共享变量的原子操作:JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作

《Jave并发编程的艺术》学习笔记(1-2章)相关推荐

  1. 《Java并发编程的艺术》笔记

    <Java并发编程的艺术>笔记 第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换. 减少上下文切换的方法有4种 ...

  2. 《Java并发编程实践》学习笔记之一:基础知识

    <Java并发编程实践>学习笔记之一:基础知识 1.程序与进程 1.1 程序与进程的概念 (1)程序:一组有序的静态指令,是一种静态概念:  (2)进程:是一种活动,它是由一个动作序列组成 ...

  3. Java并发编程的艺术-阅读笔记和思维导图

    最近在坚持每天阅读<<Java并发编程的艺术>>,不但做好笔记(MarkDown格式),还做好思维导图. 如果大家感兴趣,可以可以到码云上阅读笔记和到ProcessOn上阅读思 ...

  4. 【极客时间】《Java并发编程实战》学习笔记

    目录: 开篇词 | 你为什么需要学习并发编程? 内容来源:开篇词 | 你为什么需要学习并发编程?-极客时间 例如,Java 里 synchronized.wait()/notify() 相关的知识很琐 ...

  5. 并发编程的艺术 读书笔记

    第一章 并发编程的挑战 1. 单核CPU分配运行时间给各个线程,实现多线程执行代码. 举例:看英文书时某个单词不会,先记住看到书的页数和行数,然后去查单词,查完回到看书状态,相当于上下文切换. 2. ...

  6. 《Java并发编程实战》学习笔记

    什么是并发编程? 跳出来看全局就是3部分:分工.协作.互斥 钻进去看本质:技术的本质就是背后的理论模型 并发理论基础 并发编程产生bug的原因 可见性:cpu缓存导致共享变量在多核cpu的情况下,不可 ...

  7. JAVA并发编程的艺术-读书笔记

    1.并发编程的挑战 多线程并不一定能带来性能提升,相反过多的线程导致线程创建和上下文切换有时会比单线程性能更低 无锁并发编程:根据数据id进行取模,不同的线程处理不同段的数据 死锁:资源互相等待,线程 ...

  8. 【并发编程】(学习笔记-共享模型之管程)-part3

    文章目录 并发编程-共享模型之管程-3 1.共享带来的问题 1-1 临界区 Critical Section 1-2 竞态条件 Race Condition 2.synchronized 解决方案 2 ...

  9. [转] 《Java并发编程的艺术》笔记

    转自https://gitee.com/Corvey/note 作者:Corvey 第一章 并发编程的挑战 略 第二章 Java并发机制的底层实现原理 volatile的两条实现原则: Lock前缀指 ...

最新文章

  1. JS引用类型(6)——基本包装类型1
  2. PICRUSt2:OTU或ASV等16S随便预测宏基因组且数据库增加10倍
  3. Java-Runoob-高级教程-实例-字符串:13. Java 实例 - 字符串格式化
  4. 带通 带阻滤波器 幅频响应_二阶有源带通滤波器设计
  5. 计算机用于数据管理经历了,管理系统中计算机应用--期中测验答案
  6. arcgis for javascript ArcGISDynamicMapServiceLayer 过滤图层点
  7. RequireJS简单教程
  8. docker下载和安装
  9. 芝麻信用倒逼银行改革,纷纷模仿支付宝推出借呗!
  10. 琪琪格不因为漂亮而自信
  11. 用JQuery或JS改变div的id的五种方法
  12. Python 中的 sequence 类型
  13. 【安卓学习之互动直播】 腾讯云直播 1 - 注册/登录/个人信息
  14. 【零信任落地案例】启明星辰中国移动某公司远程办公安全接入方案
  15. JZOJ3395. 【NOIP2013模拟】Freda的传呼机
  16. ijkplayer源码---FFPlayer结构体4 SDL_Aout
  17. 大力智能学习灯,护眼助学有诀窍
  18. Flutter开发(二十九):Flutter热重启、热加载、调试与发布应用
  19. 手把手教你选Google Play ASO关键词(附实用工具)
  20. 计算机院校都看重保研er的哪些能力?

热门文章

  1. JS控制字体大小中、设为首页、收藏本站功能、超链接去掉颜色
  2. 【SNS】什么是精英?什么是草根?为什么要SNS?
  3. 数据类型的作用及基本数据类型分类
  4. 聊聊kafka consumer offset lag increase异常
  5. 三次技术转型的我在帝都的北漂奋斗史
  6. 【C++入门篇】深入理解函数重载
  7. 用R进行文本分析初探——以《红楼梦》为例
  8. java swing 下拉复选框_Java Swing JCheckBox复选框的实现方法
  9. 知识产权贯标认证的好处,如何申请?
  10. 微信授权redirect_uri域名与后台配置不一致10003