引言

多线程的知识点是一个庞大的体现,对此也是一知半解。一直想系统的深入的学习多线程的知识,奈何一直没有找到机会,好吧,其实就是懒。最近在项目中接触到一个多并发的项目,在项目中踩了无数的坑。在此下定决心做一个并发的学习笔记。

为什么并发会有安全问题

当两个线程同时对一个共享可变变量进行操作时,例如:

两个线程对变量i=1同时执行i++操作。执行完毕后i可能并不等于3而是等于2。因为i++不是原子性的操作,i++实际上是有三个步骤

第一步:读取,从主内存中将i=1读取到本地内存中。

第二步:修改,i自增。

第三部:写入,将i=2写会到缓存中。

所以当两个线程同时将i读取到工作内存中,并分别将变量i赋值为2。

原子性

原子性是指一个操作是不可中断的,要么全部执行成功要么全部执行失败,有着“同生共死”的感觉。及时在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程所干扰。

可见性

可见性是指当一个线程修改了共享变量后,其他线程能够立即得知这个修改。为什么要这样说?难道一个线程修改了共享变量其他线程不一定会立即得知这个变量的修改?没错事实确实如此。
简单的举一个例子。

数据 i 是存储在主内存中的,当一个线程执行 i++ 操作的时候首先将 i 从主内存读取到自己线程的工作内存中(也就是缓冲行),然后将工作内存的 i 执行+1操作。如果是单线程程序,在没有其他写入操作的情况下读取这个值,首先会读取缓冲行,缓存命中。那么总能得到 +1 操作之后的值。

但是多线程环境结果则会违背我们的直觉。

由于操作系统的执行,我们并不知道工作内存中的值何时才能被写入到主内存中(理由很简单,我们不可能每次修改了缓存,操作系统就会将值瞬间刷入到主内存吧?这样效率会多低呀)。所以如果这之前另一个线程从主内存读取 i 的值到本地工作内存中。那么他可能并不会感知到另一个线程其实已经修改了 i 的值。

为什么synchronized和volatile可以实现可见性我们在后续会继续介绍。

有序性

在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序

为什么要进行重排序?

比如三个操作之间是没有逻辑关系的,那么是一个cpu串行执行三个操作快还是将三个操作分别给三个cpu同时执行快呢?答案显而易见。

但是带来的一个弊端就是,可能代码的执行顺序与我们的意愿相违背。

如何让程序具备有序性,我们在后续会继续介绍。

如何避免并发问题

1.不在线程之间共享该状态变量。

2.将状态变量修改为不可变的变量。

3.在访问状态变量时使用同步。

锁的原理

在介绍原理之前我们需要了解什么是CAS自旋转,CAS自旋也就是我们常说的乐观锁,他不会发生线程阻塞,当我们将修改后的共享变量写回内存的时候,会检查在此期间这个共享变量是否被别的线程操作,如果被别的线程操作了,那么就回写内存失败,重新执行代码。(这样的好处在于对于同步块执行时间较短,上下文切换的代价是非常大的)

锁一共有4个状态,级别从低到高依次是:无所状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争逐渐升级,但是不能降级。并且这4个状态是存储在对象头中的。对象头中的Mark Word信息如下图所示(每一行代表一个状态)

  1. 一个对象刚创建的时候是无锁状态,当第一个线程a打算访问同步块应获取锁的时候,会检查是否偏向锁,发现此时为0,则使用CAS操作将Mark Word中的来线程ID设置为自己的的线程ID。然后将是否偏向锁设置为1。以后该线程在进入和退出同步块的时候不需要进行CAS操作来加锁和解锁,只需要简单的测试一下线程ID是否指向自己即可。
  2. 当另一个线程b打算访问同步块,此时与之前的线程a发生竞争,此时就要执行偏向锁的撤销。首先发出暂停线程a的指令,如果线程a还存活并且在代码块中。那么线程a在执行到安全点的时候会安全退出。
    线程b检查是否存活或者是否已经退出同步块:

    • 如果不存活或者已退出同步块则将对像头设置为无锁状态(也就是将是否偏向锁设置为0)。然后重复步骤一,使用CAS操作将Mark Word中的来线程ID设置为自己的的线程ID。
    • 如果存活并且在还在同步块当中,则将锁升级为轻量级锁。
  3. 轻量级锁轻量级锁是相对于重量级锁而言的。使用轻量级锁时,不需要申请互斥量,仅仅将Mark Word中的部分字节CAS更新指向线程栈中的Lock Record,如果更新成功,则轻量级锁获取成功,记录锁状态为轻量级锁;如果CAS更新失败,说明已经有线程获得了轻量级锁,目前发生了锁竞争(不适合继续使用轻量级锁),接下来膨胀为重量级锁。
  4. 重量级别的锁底层直接与操作系统打交道,也就是我们平常说的阻塞,线程会发生阻塞,当竞争线程释放锁的时候,才会唤醒阻塞线程。

在博客中发现一个大佬画的图还是蛮详细的,大家可以参考参考

参考:浅谈偏向锁、轻量级锁、重量级锁

java并发编程(1) --并发基础及其锁的原理的更多相关文章

  1. Java并发编程系列-(4) 显式锁与AQS

    4 显示锁和AQS 4.1 Lock接口 核心方法 Java在java.util.concurrent.locks包中提供了一系列的显示锁类,其中最基础的就是Lock接口,该接口提供了几个常见的锁相关 ...

  2. Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析

    相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...

  3. Java并发编程系列-(8) JMM和底层实现原理

    8. JMM和底层实现原理 8.1 线程间的通信与同步 线程之间的通信 线程的通信是指线程之间以何种机制来交换信息.在编程中,线程之间的通信机制有两种,共享内存和消息传递. 在共享内存的并发模型里,线 ...

  4. Java并发编程:并发容器之CopyOnWriteArrayList(转载)

    Java并发编程:并发容器之CopyOnWriteArrayList(转载) 原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW ...

  5. Java并发编程:并发容器之ConcurrentHashMap(转载)

    Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...

  6. Java并发编程:并发容器之ConcurrentHashMap

    转载: Java并发编程:并发容器之ConcurrentHashMap JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的 ...

  7. Java并发编程:并发容器之CopyOnWriteArrayList

    转载: Java并发编程:并发容器之CopyOnWriteArrayList Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个 ...

  8. Java并发编程:并发容器ConcurrentHashMap

    Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...

  9. 【Java并发编程】并发编程大合集-值得收藏

    http://blog.csdn.net/ns_code/article/details/17539599这个博主的关于java并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用 ...

  10. 【转】Java并发编程:并发容器之CopyOnWriteArrayList

    Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...

随机推荐

  1. 深度学习之 TensorFlow(四):卷积神经网络

    基础概念: 卷积神经网络(CNN):属于人工神经网络的一种,它的权值共享的网络结构显著降低了模型的复杂度,减少了权值的数量.卷积神经网络不像传统的识别算法一样,需要对数据进行特征提取和数据重建,可以直 ...

  2. gawk编程语言

    gawk是一门功能丰富的编程语言,你可以通过它所提供的各种特性来编写好几程序处理数据. 22.1 使用变量 gawk编程语言支持两种不同类型的变量: 内建变量和自定义变量 22.1.1 内建变量 ga ...

  3. LVM基本应用,扩展及缩减实现!

    LVM概述 [百度百科] LVM是逻辑盘卷管理(LogicalVolumeManager)的简称,它是Linux环境下对磁盘分区进行管理的一种机制,LVM是建立在硬盘和 分区之上的一个逻辑层,来提高磁 ...

  4. 第六章 MySQL 查询

    查询数据表 语法: SELECT {* | <字段列表>} [ FROM <表1>, <表2>.... [ where <表达式> ] [ group ...

  5. Maven学习(六)-- Maven与Eclipse整合

    由于我使用的是IDEA所以就不摘录了,感兴趣的移步 Maven学习总结(六)--Maven与Eclipse整合 Maven学习总结(七)--eclipse中使用Maven创建Web项目  

  6. pycharm linux版快捷方式创建

    ****************************pycharm_linux安装and快捷方式创建******************1.下载好安装包之后解压:    tar -xfz 压缩包名 ...

  7. Linux 操作系统基础知识

    1.操作系统总体介绍 •CPU: 就像人的大脑,主要负责相关事情的判断以及实际处理的机制.查询指令: cat /proc/cpuinfo•内存: 大脑中的记忆区块,将皮肤.眼睛等所收集到的信息记录起来 ...

  8. Ajax+Spring MVC实现跨域请求(JSONP)(转)

    背景: AJAX向后台(springmvc)发送请求,报错:已阻止交叉源请求:同源策略不允许读取 http://127.0.0.1:8080/DevInfoWeb/getJsonp 上的远程资源.可 ...

  9. SSM-SpringMVC-05:SpringMVC视图解析器InternalResourceViewResolver配置

     ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 视图解析器------默认就有配置,但是默认的在实际使用过程中有很多不方便的地方,所以我们配置一道视图解析器 ...

  10. 《Systems Performance》阅读笔记及收获

    本文共三部分: 笔记之前的废话是和书结缘的过程: Systems Performance笔记是正文,记录了读书笔记以及一些实践: 一些优化记录将之前做的一些优化归纳起来,同时也能反思做的如何,加入跟G ...