volatile、synchronized、锁的升级、原子操作、总线锁、缓存锁、CAS
2018-01-10 17:33
1016 查看
参考:《Java并发编程的艺术》
2、死锁问题。
3、资源限制(带宽、硬盘、CPU)。
所以多使用JDK并发包提供的工具。
是轻量级的synchronized,在多处理器开发中,保证共享变量的可见性。它不会引起上下文的切换。
被其修饰的变量,在写操作时,生成的汇编代码,会多一条Lock前缀的指令。为了提高处理速度,处理器不直接和内存进行通信,而是先把内存数据读到内部缓存。操作完不知何时写会内存。Lock前缀指令作用(也是对“缓存一致性协议”的实现):
1、将当前处理器缓存行的数据写回到系统内存。
2、这个写操作会使得其它CPU里,缓存了这个内存地址的数据无效。
2、当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程会从主内存中读取共享变量。volatile与锁具有相同的内存语义。
2、原子性。单个volatile读写具有原子性,但是对于多个volatile操作或者类似于volatile++这种复合操作不具有原子性。
3、禁止指令重排序。
(重排序知识参考:三 Java内存模型(JMM))
2、使用CAS的原子条件更新来实现线程间的同步
3、配合volatile、CAS读写内存语义实现内存间通信
这些就是concurrent包实现的基石。
有普通同步方法(锁是实例对象)、静态同步方法(Class对象)、同步块。是基于进入和退出Monitor实现的。
同步方法是隐式的,即无需通过字节码指令来控制,调用方法时,会检查ACC_SYNCHRONIZED标志是否被设置,如果是,执行线程会要求先成功持有Monitor。同步代码块,是通过monitorenter和monitorexit实现的。每个monitorenter指令必须执行monitorexit指令,所以编译器会自动产生一条athrow指令来做异常处理。
《synchronized锁代码演示》
1、偏向锁:等到竞争出现才会释放锁。
2、轻量级锁:CAS加锁解锁。
加锁的过程:代码进入同步块的时候,如果同步对象没有被锁定,那么JVM会在当前线程的栈帧中建立一个名为锁记录的空间(Lock Record),用来存锁对象Mark Word的拷贝(这个拷贝叫Displaced Mark Word),然后用CAS操作把对象的Mark Word,更新为指向Lock Record。
如果有其它线程来竞争锁,那么锁会膨胀成重量级锁。锁只会升级。此时其他线程获取锁时,都会被阻塞,持有锁的线程释放后,唤醒这些线程。
锁消除:JVM编译时,会去除不可能存在共享资源竞争的锁。
当一个处理器在总线上输出 LOCK#信号,其他处理器的请求将被阻塞。那么该处理器就可以独占共享内存。
CAS三大问题
1、ABA问题。
解决思路,使用版本号。AtomicStampedReference的compareAndSet比较引用、标志。
2、循环时间长开销大。
如果JVM支持CPU的pause。第一可以延迟流水线执行指令,减少CPU消耗。第二避免在退出循环的时候,因为内存顺序冲突而引起CPU流水线被清空,提高CPU执行效率。
3、只能保证一个共享变量的原子操作。
AtomicReference类来保证对象之间的原子性,把多个变量放在一个对象里来进行CAS操作。
并发编程的挑战
1、为了让程序更快,起更多线程。但是线程的上下文切换,会有额外的开销,影响运行速度。2、死锁问题。
3、资源限制(带宽、硬盘、CPU)。
所以多使用JDK并发包提供的工具。
Java并发机制底层实现原理
Java中的大部分容器和框架都依赖于volatile和原子操作的实现原理。volatile
volatile(易变的,不稳定的)是轻量级的synchronized,在多处理器开发中,保证共享变量的可见性。它不会引起上下文的切换。
被其修饰的变量,在写操作时,生成的汇编代码,会多一条Lock前缀的指令。为了提高处理速度,处理器不直接和内存进行通信,而是先把内存数据读到内部缓存。操作完不知何时写会内存。Lock前缀指令作用(也是对“缓存一致性协议”的实现):
1、将当前处理器缓存行的数据写回到系统内存。
2、这个写操作会使得其它CPU里,缓存了这个内存地址的数据无效。
volatile内存语义
1、当写变量时,会把本地内存中的值刷新到主内存中。2、当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程会从主内存中读取共享变量。volatile与锁具有相同的内存语义。
volatile特征
1、线程可见性。一个行程修改了volatile修饰的变量,其他线程可以立刻看到修改的值。2、原子性。单个volatile读写具有原子性,但是对于多个volatile操作或者类似于volatile++这种复合操作不具有原子性。
3、禁止指令重排序。
(重排序知识参考:三 Java内存模型(JMM))
concurrent包的实现
1、声明共享变量为volatile2、使用CAS的原子条件更新来实现线程间的同步
3、配合volatile、CAS读写内存语义实现内存间通信
这些就是concurrent包实现的基石。
synchronized
重量级锁。JDK1.6之后,synchronized和ReentrantLock性能基本持平。1.6中为了减少获得与释放锁的额外消耗,引入了偏向锁、轻量级锁、锁升级、锁的存储结构。synchronized实现同步的基础:java中每一个对象都可以作为锁。有普通同步方法(锁是实例对象)、静态同步方法(Class对象)、同步块。是基于进入和退出Monitor实现的。
同步方法是隐式的,即无需通过字节码指令来控制,调用方法时,会检查ACC_SYNCHRONIZED标志是否被设置,如果是,执行线程会要求先成功持有Monitor。同步代码块,是通过monitorenter和monitorexit实现的。每个monitorenter指令必须执行monitorexit指令,所以编译器会自动产生一条athrow指令来做异常处理。
《synchronized锁代码演示》
锁的升级
偏向锁 ---> 轻量级锁 ---> 重量级锁1、偏向锁:等到竞争出现才会释放锁。
2、轻量级锁:CAS加锁解锁。
加锁的过程:代码进入同步块的时候,如果同步对象没有被锁定,那么JVM会在当前线程的栈帧中建立一个名为锁记录的空间(Lock Record),用来存锁对象Mark Word的拷贝(这个拷贝叫Displaced Mark Word),然后用CAS操作把对象的Mark Word,更新为指向Lock Record。
如果有其它线程来竞争锁,那么锁会膨胀成重量级锁。锁只会升级。此时其他线程获取锁时,都会被阻塞,持有锁的线程释放后,唤醒这些线程。
锁消除:JVM编译时,会去除不可能存在共享资源竞争的锁。
原子操作的实现原理
原子操作:不可被中断的一个或一系列操作。CPU处理器如何实现原子操作
首先处理器会自动保证基本的内存操作的原子性。保证从内存中读取或写入一个字节是原子性的。意思是当一个处理器从系统内存读取一个字节时,其他处理器不能访问这个字节的内存地址。但是复杂的内存操作,处理器不能自动保证其原子性,比如跨总线宽度、跨多个缓存行、跨页表。但是提供缓存加锁和总线加锁。总线锁
数据通过总线在处理器和内存之间传递。每次数据传递是通过一系列的步骤步骤来完成,叫做总线事务,在一个事务期间,总线会禁止其他处理器和IO设备执行内存读写。总线仲裁(Bus Arbitration),会确保所有处理器都能公平访问内存。当一个处理器在总线上输出 LOCK#信号,其他处理器的请求将被阻塞。那么该处理器就可以独占共享内存。
缓存锁
锁操作回写内存时,修改内部内存地址,缓存一致性会使得其他CPU的缓存失效。Java中如何实现原子操作
通过锁和循环CAS实现。CAS
JVM的CAS操作利用的是处理器提供的CMPXCHG指令实现的。CAS三大问题
1、ABA问题。
解决思路,使用版本号。AtomicStampedReference的compareAndSet比较引用、标志。
2、循环时间长开销大。
如果JVM支持CPU的pause。第一可以延迟流水线执行指令,减少CPU消耗。第二避免在退出循环的时候,因为内存顺序冲突而引起CPU流水线被清空,提高CPU执行效率。
3、只能保证一个共享变量的原子操作。
AtomicReference类来保证对象之间的原子性,把多个变量放在一个对象里来进行CAS操作。
synchronized和CAS比较
synchronized是互斥锁,会有线程阻塞和唤醒带来额外的消耗,称作阻塞同步,也可称作悲观锁。CAS是非阻塞同步,称作乐观锁。先进行操作,操作完成再判断是否成功,是否有并发问题,有则进行失败补偿,没有就算操作成功。相关文章推荐
- Java并发编程读书笔记——volatile、synchronized和原子操作(CAS机制详解)
- 分布式缓存--序列3--原子操作与CAS乐观锁
- 深入理解Volatile,synchronized,原子操作的必要性
- 原子级操作 volatile和synchronized
- i++不是原子操作,看似简单,实则巨坑的一个线程同步的问题。synchronized 和 volatile
- 原子级操作 volatile和synchronized
- Java单例的由浅入深----懒汉式的升级(2 原子操作、指令重排)懒汉式的最终版本(volatile)
- volatile能保证long&double类型变量操作的原子性
- atomicity and volatility 代替synchronized 对象锁 的另一种方法(原子操作+可见性)
- volatile关键字不具备synchronized关键字的原子性(同步),Atomic前缀修饰变量 具有原子性
- java 线程之synchronized,volatile,原子类,Lock锁相关
- CAS原子操作实现无锁及性能分析
- 关于原子操作和volatile关键字~
- 从volatile说到,i++原子操作,线程安全问题
- Java多线程之原子操作atomic的使用CAS(七)
- volatile和原子操作
- (转)关于volatile和原子操作研究的插曲
- i++ 是否为原子操作 和 Java中的volatile关键字
- java的原子操作和volatile
- 原子变量、volatile、synchronized的可见性和原子性比较