synchronized细节

之前面试京东健康的时候被问到的问题:synchronized与Lock的区别是什么,关于synchronized的底层实现没回答得很详细,因此在此记录下

synchronized的作用主要有三个:

  1. 原子性:确保线程互斥的访问同步代码;
  2. 可见性:保证共享变量的修改能够及时可见,其实是通过Java内存模型中的 “对一个变量unlock操作之前,必须要同步到主内存中;如果对一个变量进行lock操作,则将会清空工作内存中此变量的值,在执行引擎使用此变量前,需要重新从主内存中load操作或assign操作初始化变量值” 来保证的;
  3. 有序性:有效解决重排序问题,即 “一个unlock操作先行发生(happen-before)于后面对同一个锁的lock操作”;
    Synchronized总共有三种用法:
  4. 当synchronized作用在实例方法时,监视器锁(monitor)便是对象实例(this);
  5. 当synchronized作用在静态方法时,监视器锁(monitor)便是对象的Class实例,因为Class数据存在于永久代,因此静态方法锁相当于该类的一个全局锁;
  6. 当synchronized作用在某一个对象实例时,监视器锁(monitor)便是括号括起来的对象实例;
同步原理

对于同步代码块来说,他是依赖于monitor这个监视器的,每个对象天生的就是一个monitor,所谓锁定的状态也就是monitor被占用了。
占用monitor的指令:monitorenter
这个指令意味着,如果当前monitor没有被占用,那么占用他,如果已经被占用了,且当前线程不是占用的线程,那么阻塞当前线程,如果是占用的线程,那么实现可重入。
释放monitor的指令:monitorexit。
对于同步方法来说
字节码没有显式的指明使用monitor而是使用了**ACC_SYNCHRONIZED **标识符,实际上他也是依赖monitoir实现的。
而monitor的再底层,是使用操作系统的信号量实现的,因此使用monitor会导致系统调用,对性能有所消耗

锁的优化

在对象头的mark word中说明了锁可以分为几个状态,无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。需要注意的是这个转换的过程是单向的,无法逆转。
偏向锁
当前锁始终处于单线程使用的状态时,使用偏向锁。当有另外一个线程访问此锁时(即使没有竞争),锁会变为轻量级锁

轻量级锁
如果当前锁不存在并发访问,也就是说不存在锁的争用那么就会使用轻量级锁,与偏向锁的区别在于,偏向锁只允许一个线程占用锁,而轻量级锁允许多个线程,只要是来回切换,避免争抢锁就行。如果发生了锁争抢,那么轻量级锁膨胀为重量级锁。

重量级锁
也就是之前说的基于monitor的锁。性能消耗大。

自旋锁
很多时候,获取了锁的线程并不需要使用多久,特别是那些代码块短的程序。此种情况下,如果发生了线程争用,我们可以先不将程序挂起,而是让他while循环个几百圈。毕竟挂起线程,恢复线程都是需要消耗资源的。

锁消除
有些时候,我们加了锁,但是这个锁却永远不会起作用,这可并不是由于我们写的程序不完整。如string的拼接,使用了stringbuffer,众所周知stringbuffer是线程安全的,但是在此处他的锁永远不会起作用,因此可以进行锁消除。

锁粗化
多个分割的同步代码块有时我们可以把它合并为一块。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值