java并发编程(1) --并发基础及其锁的原理
引言
多线程的知识点是一个庞大的体现,对此也是一知半解。一直想系统的深入的学习多线程的知识,奈何一直没有找到机会,好吧,其实就是懒。最近在项目中接触到一个多并发的项目,在项目中踩了无数的坑。在此下定决心做一个并发的学习笔记。
为什么并发会有安全问题
当两个线程同时对一个共享可变变量进行操作时,例如:
两个线程对变量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信息如下图所示(每一行代表一个状态)

- 一个对象刚创建的时候是无锁状态,当第一个线程a打算访问同步块应获取锁的时候,会检查是否偏向锁,发现此时为0,则使用CAS操作将Mark Word中的来线程ID设置为自己的的线程ID。然后将是否偏向锁设置为1。以后该线程在进入和退出同步块的时候不需要进行CAS操作来加锁和解锁,只需要简单的测试一下线程ID是否指向自己即可。
- 当另一个线程b打算访问同步块,此时与之前的线程a发生竞争,此时就要执行偏向锁的撤销。首先发出暂停线程a的指令,如果线程a还存活并且在代码块中。那么线程a在执行到安全点的时候会安全退出。
线程b检查是否存活或者是否已经退出同步块:- 如果不存活或者已退出同步块则将对像头设置为无锁状态(也就是将是否偏向锁设置为0)。然后重复步骤一,使用CAS操作将Mark Word中的来线程ID设置为自己的的线程ID。
- 如果存活并且在还在同步块当中,则将锁升级为轻量级锁。
- 轻量级锁轻量级锁是相对于重量级锁而言的。使用轻量级锁时,不需要申请互斥量,仅仅将Mark Word中的部分字节CAS更新指向线程栈中的Lock Record,如果更新成功,则轻量级锁获取成功,记录锁状态为轻量级锁;如果CAS更新失败,说明已经有线程获得了轻量级锁,目前发生了锁竞争(不适合继续使用轻量级锁),接下来膨胀为重量级锁。
- 重量级别的锁底层直接与操作系统打交道,也就是我们平常说的阻塞,线程会发生阻塞,当竞争线程释放锁的时候,才会唤醒阻塞线程。
在博客中发现一个大佬画的图还是蛮详细的,大家可以参考参考

java并发编程(1) --并发基础及其锁的原理的更多相关文章
- Java并发编程系列-(4) 显式锁与AQS
4 显示锁和AQS 4.1 Lock接口 核心方法 Java在java.util.concurrent.locks包中提供了一系列的显示锁类,其中最基础的就是Lock接口,该接口提供了几个常见的锁相关 ...
- Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析
相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...
- Java并发编程系列-(8) JMM和底层实现原理
8. JMM和底层实现原理 8.1 线程间的通信与同步 线程之间的通信 线程的通信是指线程之间以何种机制来交换信息.在编程中,线程之间的通信机制有两种,共享内存和消息传递. 在共享内存的并发模型里,线 ...
- Java并发编程:并发容器之CopyOnWriteArrayList(转载)
Java并发编程:并发容器之CopyOnWriteArrayList(转载) 原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW ...
- Java并发编程:并发容器之ConcurrentHashMap(转载)
Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...
- Java并发编程:并发容器之ConcurrentHashMap
转载: Java并发编程:并发容器之ConcurrentHashMap JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的 ...
- Java并发编程:并发容器之CopyOnWriteArrayList
转载: Java并发编程:并发容器之CopyOnWriteArrayList Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个 ...
- Java并发编程:并发容器ConcurrentHashMap
Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...
- 【Java并发编程】并发编程大合集-值得收藏
http://blog.csdn.net/ns_code/article/details/17539599这个博主的关于java并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用 ...
- 【转】Java并发编程:并发容器之CopyOnWriteArrayList
Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...
随机推荐
- Dynamic 中修改实体中主字段的长度
select EntityId,* from MetadataSchema.Entity where Name='dji_incidentaddress' SELECT TOP 100 [Attrib ...
- 前端开发APP,从HBuilder开始~ 【转】
内容简介 介绍目前前端人员开发app的几种方法,具体介绍hbuilder开发app,一扇赞新的大门~ 无所不能的js 最开始js仅仅局限于网页上一些效果,操作网页内容等, 但是nodejs把js带入了 ...
- 洛谷 P1129 解题报告
P1129 [ZJOI2007]矩阵游戏 题目描述 小\(Q\)是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏.矩阵游戏在一个\(N*N\)黑白方阵进行(如同国际象棋一般 ...
- Http Header信息
REMOTE_ADDR – 访问客户端的 IP 地址 HTTP_VIA – 如果有该条信息, 就证明您使用了代理服务器,代理服务器的地址就是后面的数值. HTTP_X_FORWARDED_FOR – ...
- Windows安装TensorFlow
1.下载安装Anaconda 官方地址:https://www.continuum.io/downloads/镜像地址:https://mirrors.tuna.tsinghua.edu.cn/ana ...
- PAT1011:World Cup Betting
1011. World Cup Betting (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Wit ...
- MVP架构在xamarin android中的简单使用
好几个月没写文章了,使用xamarin android也快接近两年,还有一个月职业生涯就到两个年了,从刚出来啥也不会了,到现在回头看这个项目,真jb操蛋(真辛苦了实施的人了,无数次吐槽怎么这么丑),怪 ...
- 关于二叉查找树的一些事儿(bst详解,平衡树入门)
最近刚学了平衡树,然后突发奇想写几篇博客纪念一下,可能由于是刚学的缘故,还有点儿生疏,望大家海涵 说到平衡树,就不得不从基础说起,而基础,正是二叉查找树 什么是二叉查找树?? 大家观察一下下面的这棵二 ...
- js文件引用的问题顺带复习css引用
js文件包含在<script>块中用scr引用,css在link和@import来引用,css不是本篇的重点,直接引用一个博主的总结: “ 区别1:link是XHTML标签,除了加载CSS ...
- JavaScript 设计模式之----单体(单例)模式
设计模式之--单体(单例)模式 1.介绍 从本章开始,我们会逐步介绍在JavaScript里使用的各种设计模式实现,在这里我不会过多地介绍模式本身的理论,而只会关注实现.OK,正式开始. 在传统开发工 ...