Syncronized解析

作用:

)确保线程互斥的访问同步代码

)保证共享变量的修改能够及时可见

)有效解决重排序问题。

用法:

)修饰普通方法(锁是当前实例对象)

)修饰静态方法(锁是当前对象的Class对象)

)修饰代码块(锁是Synchonized括号里配置的对象)

底层实现原理:

方法和代码块都是基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。

(1)代码块同步是使用monitorenter和monitorexit指令实现,monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处

每个对象有一个监视器锁(monitor)。线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

,该线程即为monitor的所有者。

、如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.

,再重新尝试获取monitor的所有权。

执行monitorexit的线程必须是锁对象所对应的monitor的所有者。

,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个
monitor 的所有权。

(2)方法同步是使用ACC_SYNCHRONIZED标示符实现的

相对于普通方法,常量池中多了ACC_SYNCHRONIZED标示符。当方法调用时,将会检查方法的
ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。

讲jdk1.6锁优化前的前置知识



锁的状态保存在java对象头中,那对象头是什么?

块区域:对象头、实例数据、对齐补充。(jvm知识)

对象头结构如下:

CAS:Compare and Swap,比较并设置。用于在硬件层面上提供原子性操作。比较是否和给定的数值一致,如果一致则修改,不一致则不修改。

Synchronized在jdk1.6的优化



Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex
Lock(互斥锁)来实现的,这个成本非常高,这就是为什么Synchronized效率低的原因。因此,这种依赖于操作系统Mutex Lock所实现的锁我们称之为“重量级锁”。JDK中对Synchronized做的种种优化,其核心都是为了减少这种重量级锁的使用。JDK1.6以后,为了减少获得锁和释放锁所带来的性能消耗,提高性能,引入了“轻量级锁”和“偏向锁”。

锁的状态总共有四种:

1.重量级锁(依赖操作系统的互斥锁)

2.轻量级锁(在无竞争的情况下使用CAS操作去消除同步使用的互斥量,默认开始就是这个)

3.偏向锁(在无竞争的情况下把整个同步都消除掉,连CAS操作都不做了)

4.无锁状态

随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁(但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级)

位的JDK为例:

无锁和重量级(操作系统的互斥锁)不用解释了,重点解释轻量级锁和偏向锁。

轻量级锁

时,膨胀为重量级锁。

轻量级锁解锁:轻量级解锁时,会使用原子的CAS操作来将栈帧中DisplacedMark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。

偏向锁

,偏向模式。

偏向锁加锁过程:

当锁对象第一次被线程获取的时候,虚拟机将会把对象头中的标志位设为“01”,即偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的Mark
Word之中,如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作

偏向锁的撤销:

当有另外一个线程去尝试获取这个锁时,偏向模式就宣告结束。 根据锁对象目前是否处于被锁定的状态,撤销偏向(Revoke Bias)后恢复到未锁定(标志位为“01”)或轻量级锁定(标志位为“00”)的状态,后续的同步操作就如上面介绍的轻量级锁那样执行

三种锁状态的总结

相关的扩展:

1.  Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

2.上文提到的偏向锁、轻量级锁都是jdk1.5到1.6的锁优化技术中的。锁优化技术还有如下:

适应性自旋:

互斥同步对性能最大的影响是阻塞的实现,因为挂起线程和恢复线程都是OS内核态完成的。那么使用自旋(即忙循环等待),不去阻塞地等待,这就是自旋锁技术。然而,自旋需要占用CPU时间,时间短还好,时间长了浪费性能,而适应性地根据同一个锁上的自旋时间及锁的拥有者状态决定时间,就是适应性自旋技术。

锁消除:

即时编译期运行时,有些代码上的同步,被检测到不可能存在数据竞争的锁,进行消除。检测依据来源于逃逸分析技术。

锁粗化:

如果一个方法里有A、B、C三句代码,都分别进行了三次Synchronized(this),其实没必要,反而增加了加锁解锁的消耗,这种情况会直接粗化为一个大Synchronized。

参考:

《深入理解Java虚拟机》

《Java并发编程艺术》

http://www.cnblogs.com/paddix/p/5405678.html

http://ifeve.com/java-synchronized/

Java并发编程总结(一)Syncronized解析的更多相关文章

  1. Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  2. (转)Java并发编程:volatile关键字解析

    转:http://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或 ...

  3. Java并发编程:volatile关键字解析(转载)

    转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析   Java并发编程:volatile关键字解析 ...

  4. Java并发编程:volatile关键字解析-转

    Java并发编程:volatile关键字解析 转自海子:https://www.cnblogs.com/dayanjing/p/9954562.html volatile这个关键字可能很多朋友都听说过 ...

  5. Java并发编程中的设计模式解析(二)一个单例的七种写法

    Java单例模式是最常见的设计模式之一,广泛应用于各种框架.中间件和应用开发中.单例模式实现起来比较简单,基本是每个Java工程师都能信手拈来的,本文将结合多线程.类的加载等知识,系统地介绍一下单例模 ...

  6. Java并发编程:volatile关键字解析(学习总结-海子)

    博文地址:Java并发编程:volatile关键字解析

  7. 6、Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  8. 转:Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字, ...

  9. [转载]Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  10. 干货:Java并发编程必懂知识点解析

    本文大纲 并发编程三要素 原子性 原子,即一个不可再被分割的颗粒.在Java中原子性指的是一个或多个操作要么全部执行成功要么全部执行失败. 有序性 程序执行的顺序按照代码的先后顺序执行.(处理器可能会 ...

随机推荐

  1. Maven学习归纳(五)——继承与聚合实例讲解

    一.Maven的继承 1.1 什么是继承? 继承:父工程拆分出很多子工程,可以通过父工程,统一管理依赖的版本 1.2 为什么要使用继承呢? 在A.jar 依赖着——>B.jar依赖着——> ...

  2. C#委托(delegate、Action、Func、predicate)和事件

    一.前言 刚开始工作的时候,觉得委托和事件有些神秘,而当你理解他们之后,也觉得好像没有想象中的那么难.在项目中运用委托和事件,你会发现他非常棒,这篇博文算是自己对委托和事件的一次梳理和总结. 二.委托 ...

  3. HBase工作中的一些优化方法

    1.表的设计 Pre-creating Regions(预分区) 默认情况下,在创建Hbase表的时候会自动创建一个region分区,当导入数据的时候,所有的Hbase客户端都向这一个region写数 ...

  4. DevExpress的TextEdit、RadioGroup、ColorPickEdit设置默认值

    场景 Winform中实现ZedGraph的多条Y轴(附源码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1001322 ...

  5. JAVA中的内存们

    我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区,用户磁盘和CPU的交互,而CPU运转速度越来越快,磁盘远远跟不上CPU的读写速度,才设计了内存,用户缓冲用户IO等待导致CPU的等 ...

  6. 第二场周赛(递归递推个人Rank赛)——题解

    很高兴给大家出题,本次难度低于上一场,新生的六个题都可以直接裸递归式或者裸递推式解决,对于老生的汉诺塔3,需要找出一般式,后两题分别为裸ST算法(或线段树)/线性DP. 正确的难度顺序为 种花 角谷定 ...

  7. nfs 存储服务

    今日内容: NFS 1.什么是nfs? network file system 网络文件系统 nfs共享存储 2.nfs能干什么? nfs 能为 不同主机系统之间 实现 文件的共享 3.为什么要使用n ...

  8. Day 25 网络基础2

    ip地址划分 ip地址由32位二进制组成. 什么是二进制?0101 10进制 0-9 10 2进制 0-1 10 二进制1100 ==1X2^3+1X2^2+0X2^1+0X2^0 =12 十进制15 ...

  9. 导出wordpress数据库Fatal error: Cannot 'break' 2 levels

    今天我打算备份一下我在Linux下用宝塔面板搭建的phpmyadmin导出wordpress数据库.选择数据库后给我一个Fatal error: Cannot 'break' 2 levels in ...

  10. QTP8.2--安装流程

    一.安装说明: 1.进入安装文件夹,运行QTP8.2安装文件setup,进入安装向导后直接单击“QuickTest Professional 安装”选项,由于破解文件存在缺陷,所以请不要改变安装路径c ...