1. Synchronized概念及作用
1.1 现如今的操作系统已经步入多核时代,可以支持大量的并行并发的访问计算机资源,既然存在并行和并发则如何处理各个线程对同一资源进行修改和访问的数据安全性问题.要保证正确的并发访问手段,提供方式有互斥同步,非阻塞同步.
互斥同步: 同步是指在多个线程并发访问共享数据时,保证共享数据在同一时刻只能被一条线程访问,而互斥是实现同步的一种手段,临界区,互斥量(Mutex)和信号量都是常用的互斥实现方法,互斥是因,同步是果;互斥的是方法,同步的是目的
缺点: 互斥同步的缺点是进行线程阻塞和唤醒带来的性能开销(用户态转化,维护锁资源等等),因此这种也被称为阻塞同步.属于一种悲观的并发策略
非阻塞同步(CAS): 基于冲突检测的的乐观并发策略,也就是忽略冲突,我先操作,如果发生了冲突,即重试指导没有竞争产生,需要计算机指令集支持.
1.2 Java当然也提供了多线程的相关接口,并且java实现互斥同步的手段就是synchronized关键字,syschronized在经过Javac编译器编译后会在同步块前后分别形成monitorenter,monitorexit这两个字节码命令。这两条字节码指令一个是用来加锁,一个是用来释放锁资源并唤醒其他被阻塞挂起的线程
2.Synchronized获取锁流程
2.Synchronized重量级锁优化
2.1 由前面可以知道,我们说到了sync锁采用互斥同步的方式,而互斥同步对性能影响最大的是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态完成,这些操作给Java虚拟机的并发现带来了很大压力.因此HotSpot虚拟机开发团队实现了各种锁优化的技术.
-
自旋锁和自适应锁: 自选锁的概念是当某个线程去获取资源的时候,如果冲突了,不会立马挂起,而是让线程执行一个忙循环,看看在此期间持有锁的线程是否很快就会释放锁资源.这就是所谓的自旋锁,JDK6默认开启,默认是10次,但需要注意的是,如果线程需要占用的锁资源时间很长,则自旋锁会成为负担;自旋是要占用CPU的资源的。而自适应锁就是在自旋次数上的优化,自旋次数会根据前一次在同一个锁上的自旋时间和拥有者状态来动态调整的,而不是一个固定的次数.
-
锁消除: 即消除不必要的加锁,比如StringBuffer
-
锁粗化: 即如果一系列连续的操作都是对同一对象进行反复加锁和解锁,比如在循环中加锁,则jvm会探测这些操作,讲锁的范围粗化到整个操作序列的外部.
-
轻量级锁: 即通过CAS来避免直接的加锁
-
偏向锁: 偏向于第一个获取获取它的线程,如果在接下来的过程中没有其他线程来获取,则持有偏向锁的线程讲永远不需要进行同步
3. 锁升级的详细过程
3.1 在理解锁升级的过程中我们先来了解个概念,即对象头.在java当中是通过对象来作为监视器进行互斥同步的加锁,即语法是通过Synchronized(object)关键字,而我们 Object object=new Object();这个对象在堆中分为两部分,一个是对象头,这部分一般用来存放对象自身运行的数据,比如Hash码,GC年龄,即这部分称为Mark Word,还有指向方法区的对象类型数据指针.另一部分用于存放实例对象的数据.
而Mark Word是实现轻量级锁和偏向锁的关键地方