同步

synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性
Java中每一个对象都可以作为锁,这是synchronized实现同步的基础。

synchronized 常见的三种用法如下:

  1. 普通同步方法,锁是当前实例对象
  2. 静态同步方法,锁是当前类的class对象
  3. 同步方法块,锁是括号里面的对象

通过如下代码来分析下synchronized 获取的是哪个对象的锁

public class SynTest {private static List<String> list = new ArrayList<String>();//当前实例的锁public synchronized void add1(String s){list.add(s);}//SynTest.class 锁public static synchronized void add2(String s){list.add(s);}//SynTest.class 锁public void add3(String s){synchronized(SynTest.class){list.add(s);}}//当前实例的锁public void add4(String s){synchronized(this){list.add(s);}}
}

普通同步方法,锁是当前实例对象
add1 方法是synchronized的第一种用法,因为它是普通同步方法,所以获取当前实例的锁。
add2 方法是synchronized的第二种用法,因为它是静态同步方法,所以获取SynTest.class的锁。
add3 方法是synchronized的第三种用法。指定锁:SynTest.class。
add4 方法是synchronized的第三种用法。指定锁:this(当前实例)。

结论:

add1和add4方法的锁都是 当前实例,所以add1和add4 可以实现方法互斥
add2和add3方法的锁都是SynTest.class,所以add2和add3可以实现方法互斥。
**注意:**add1和add2两个synchronized是不互斥的,因为他们不是同一把锁。只有同一把锁才会互斥。

synchronized块编译成字节码后会在同步块的入口位置和退出位置分别插入monitorenter和monitorexit字节码指令。如下图:

monitorenter和monitorexit指令规则:
1. monitorenter在编译后插入到同步代码库的开始位置。
2. monitorexit插入在方法结束处和异常处。
3. 一个monitorenter必须保证有对应的monitorexit。
4. 任何对象都有一个monitor以之关联,当一个monitor被持有后,该对象出于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,尝试获取对象的锁。

静态方法和普通方法在编程成字节码后会在方法的访问标识字段中标识为同步方法。

方法同步的细节在JVM规范里并没有详细说明。但是,方法的同步同样可以使用这两个指令来实现。

需要提前了解知识点:java内存模型

内存可见性

synchronized关键字强制实施一个互斥锁,使得被保护的代码块在同一时间只能有一个线程进入并执行。当然synchronized还有另外一个 方面的作用:在线程进入synchronized块之前,会把工作存内存中的所有内容映射到主内存上,然后把工作内存清空再从主存储器上拷贝最新的值。而 在线程退出synchronized块时,同样会把工作内存中的值映射到主内存,但此时并不会清空工作内存。这样一来就可以强制其按照上面的顺序运行,以 保证线程在执行完代码块后,工作内存中的值和主内存中的值是一致的,保证了数据的一致性!
所以由synchronized修饰的set与get方法都是相当于直接对主内存进行操作,不会出现数据一致性方面的问题。

指令重排序

指令重排序是JVM为了优化指令,提高程序运行效率,在不影响单线程程序执行结果的前提下,尽可能地提高并行度。
synchronized块对应java程序来说是原子操作,所以说内部不管怎么重排序都不会影响其它线程执行导致数据错误。执行的指令也不会溢出方法。

happens-before

监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。

锁优化

在多线程并发编程中synchronized一直是元老级角色,很多人都会称呼它为重量级锁。在Java1.5中,synchronize是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用Java提供的Lock对象,性能更高一些。但是到了Java1.6,发生了变化。synchronize在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在Java1.6上synchronize的性能并不比Lock差。官方也表示,他们也更支持synchronize,在未来的版本中还有优化余地。

偏向锁

简单的理解,偏向于这个线程。 当一个线程进入同步块,首先测试对象的mark word 中的threadId是否等同当前线程ID,如果成功,则获取锁成功,否则。首先测试mark word中的锁标识是否为1 。如果没有设置。则升级为轻量级锁。否则 通过CAS操作,将自己的线程ID 尝试放入 的mark word 的位置。如果成功则获取锁成功。否则,说明对象存在竞争。将会在适当的地方挂起获取锁的线程。然后升级锁。接着执行代码。
偏向锁默认为开启状态。只是会在应用启动后延迟启动通过参数可以设置不延时XX:BiasedLockingStartupDelay=0。如果你确定应用程序里所有的锁通常情况下处于竞争状态,可以通过JVM参数关闭偏向锁:-XX:-UseBiasedLocking=false,那么程序默认会进入轻量级锁状态。

轻量级锁

JVM通过CAS修改对象头来获取锁,如果CAS修改成功则获取锁,如果获取失败,则说明有竞争,则通过CAS自旋一段时间来修改对象头,如果还是获取失败,则升级为重量级锁。如果没有竞争,轻量级锁使用CAS操作避免了使用互斥量的开销,但如果存在锁竞争,除了互斥量的开销外,还额外发生了CAS操作,因此在有竞争的情况下,轻量级锁会比传统的重量级锁更慢。

重量级锁

重量级锁通过对象内部的监视器(monitor)实现,其中monitor的本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态到内核态的切换,切换成本非常高。

锁消除:

锁消除是指虚拟机在即时编译器在运行时,对于一些在代码上要求同步,但是被检测到不可能存在数据竞争的锁进行消除。比如,一个锁不可能被多个线程访问到,那么在这个锁上的同步块JVM将把锁消除掉。

锁粗化

程序中一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作是出现在循环体中的,那即使没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。

for(int i=0; i<1000; i++){synchronized(this){...}
}

上面代码JVM将会优化成如下:

synchronized(this){for(int i=0; i<1000; i++){...}
}

本人简书blog地址:http://www.jianshu.com/u/1f0067e24ff8    
点击这里快速进入简书

深入理解 Synchronized相关推荐

  1. synchronized()_这篇文章带你彻底理解synchronized关键字

    Synchronized关键字一直是工作和面试中的重点.这篇文章准备彻彻底底的从基础使用到原理缺陷等各个方面来一个分析,这篇文章由于篇幅比较长,但是如果你有时间和耐心,相信会有一个比较大的收获,所以, ...

  2. 深入理解synchronized

    深入理解synchronized 线程安全问题 临界区( Critical Section) 竞态条件( Race Condition ) synchronized 的使用 加锁方式 synchron ...

  3. 理解synchronized的含义

    理解synchronized的含义 1.synchronized就是给当前的NumOps类型的对象添加了一个互斥锁机制:锁只能有一个 2.当有一个线程正在某个同步方法中执行,则其它线程不能进入该对象的 ...

  4. 并发编程之深入理解synchronized

    并发编程之深入理解synchronized 一.java共享内存带来的线程安全问题 1.1 问题分析 1.2 临界区 1.3 竞态条件 二.synchronized使用 2.1 解决之前的共享问题 三 ...

  5. synchronized不能锁静态变量_多线程编程不可错过——彻底理解synchronized

    持续分享互联网研发技术,欢迎关注我.本人是一线架构师,有问题可以沟通. 1. synchronized简介 在学习知识前,我们先来看一个现象: public class SynchronizedDem ...

  6. 让你彻底理解Synchronized

    synchronized简介 在学习知识前,我们先来看一个现象: public class SynchronizedDemo implements Runnable {private static i ...

  7. 深入理解synchronized关键字

    2019独角兽企业重金招聘Python工程师标准>>> synchronized是并发编程中重要的使用工具之一,我们必须学会使用并且掌握它的原理. 概念及作用 JVM自带的关键字,可 ...

  8. synchronized()_深入理解synchronized

    并发编程中用到最多的关键字就是synchronized.下面来探究一下synchronized: synchronized如何使用? synchronized是如何实现同步加锁的,原理是什么? syn ...

  9. 理解Synchronized

    https://www.jianshu.com/p/d53bf830fa09 1. synchronized简介 在学习知识前,我们先来看一个现象: public class Synchronized ...

最新文章

  1. 华为技术面试编码题_最佳技术编码面试准备书
  2. R语言随机森林模型:计算随机森林模型的特征重要度(feature importance)并可视化特征重要度、使用少数重要特征拟合随机森林模型(比较所有特征模型和重要特征模型在测试集上的表现差异)
  3. r语言用行名称提取数据框信息显示na_用R语言提取数据框中日期对应年份(列表转矩阵)...
  4. 中国数学相比与西方数学为什么会处于劣势?
  5. 视频导切台RGBlink 控制软件下载与测试
  6. python not in range1002无标题_17个新手常见Python运行时错误
  7. 【云隐】STM32F103C8T6实现串口IAP方式升级固件
  8. # HDU - 6185 Covering
  9. Bootstrap4+MySQL前后端综合实训-Day01-AM【实训安排、HBuilder下载及使用、双飞翼布局(圣杯布局)案例、CSS在线手册、flex布局中的对齐方式】
  10. 使用idea编写代码作为生产者,Kafka接收其发来的信息【小案例】(一)
  11. hibernate 调用oracle存储过程,hibernate调用oracle存储过程||函数
  12. 分享精心收藏的前台开发素材网站,都是干货
  13. 最全LinuxC语言系统开发资源视频资源
  14. 基于科大讯飞实现语音识别功能
  15. 如何修改hosts文件权限
  16. lcd显示c语言程序,1602液晶简单显示程序
  17. 热门!实用!游戏rpg制作素材网站推荐!
  18. 用大于一素数的最小素数替换4*4矩阵中的素数
  19. 数字签名与数字加密的区别
  20. 怎样提高工作积极性与工作效率

热门文章

  1. 期末复习、化学反应工程科目(第五章)
  2. sklearn 主成分分析法 PCA和IPCA
  3. 六、爬虫中重要的解析库xpath和BeautifulSoup
  4. 可逆神经网络(Invertible Neural Networks)详细解析:让神经网络更加轻量化
  5. 客座招生 | 中科院深圳先进院招收智能机器人方向联培和客座学生
  6. 工作之后,顶会还重要嘛?
  7. ​Transformer升级之路:从Performer到线性Attention
  8. PW Live直播 | 清华大学NLP组刘正皓:神经信息检索的进展与挑战
  9. 蓝桥备赛第二周 前缀和
  10. 在指定文件夹下打开Jupyter Notebook