多线程并发编程之Java锁相关

1 Java中锁的概念

独享锁:写锁,获得锁的线程可以修改资源,其它线程不能加锁。
共享锁:读锁,获得锁的线程只读不写,其它线程可以加读锁,不能加写锁。

乐观锁:假定没有发生冲突,如果获取的数据与之前的数据不一致,则读取最新数据;乐观锁一般会采用版本号机制或CAS算法实现。
悲观锁:假定会发生冲突,一开始就不信任对方,从读数据开始就上锁,所有对数据的操作都进行同步。Synchronized和ReentrantLock就是典型的悲观锁。

可重入锁:线程获得锁后,可以进入同一把锁同步的其它代码。
自旋锁:是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程就循环等待,不断请求锁直至锁被释放获得锁,才会退出循环,CAS就是典型的自旋锁,自旋会有次数限制,超过次数就升级锁。

2 同步关键字Synchronized

  1. 用于实例方法和代码块,锁的是实例对象
  2. 用于静态方法,锁的是Class类对象
  3. 锁的作用域:对象锁、类锁、分布式锁,Synchronized只能作为对象锁或类锁

根据JVM规范描述的实现原理,代码块同步是使用monitorenter和monitorexit指令实现的,方法同步同样可以通过这两个指令实现。

synchronized(this){
	i++;
}

我们经常可以看到类似上面这样的代码,这时synchronized是作为对象锁,锁住的是java对象,那么请思考下面几个问题

  1. 加锁的状态如何记录?
  2. 锁状态会被保存到java对象中吗?
  3. jvm是如何做到根据锁状态来进行线程挂起和唤醒的?

假装思考了几十秒后,下面开始揭晓答案
在这里插入图片描述

  • 对象头
    • Mark Word:加锁状态会被记录在这块内存区域
    • Class Meta Address:指向方法区中存放该对象类信息的地址
    • Array Length:如果是数组对象,则会记录数组长度
  • 成员变量
  • 填充字节,视32位或64位系统而定

下面具体讲解对象头中的Mark Word

锁标志位(2bit)锁状态
对象哈希码、分代年龄(4bit)、是否偏向锁(1bit)01无锁
偏向的线程ID、分代年龄(4bit)、是否偏向锁(1bit)01偏向锁
指向虚拟机栈中锁记录的指针00轻量级锁
Monitor监视器地址10重量级锁
11GC标记

在这里插入图片描述

3 偏向锁及锁的升级过程

偏向锁:HotSpot作者研究发现,在大多数情况下是不存在锁竞争的,常常是一个线程多次获得同一把锁,因此为了降低获得锁的成本,引入了偏向锁;以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁。
在JDK6以后,默认已经开启了偏向锁这个优化,通过JVM参数-XX:-UseBiasedLocking来禁用偏向锁

轻量级锁:竞争锁的线程不会挂起阻塞,而是进入自旋(CPU空转消耗CPU资源),自旋一定次数,就会升级锁。
重量级锁:多个线程争抢锁,一个线程获得锁,其它线程挂起阻塞。

默认:是
锁定
释放偏向锁
锁竞争 : 锁升级
锁升级
锁竞争 : 获取轻量级锁
对象
是否开启偏向锁
未锁定
关闭偏向锁
偏向锁锁定 : ThreadID
轻量级锁锁定 : 自旋抢锁
重量级锁锁定 : Monitor地址

参考文章

大白话聊聊Java并发面试问题之Java 8如何优化CAS性能?【石杉的架构笔记】
Java锁—偏向锁、轻量级锁、自旋锁、重量级锁
网易云课堂《Java高级开发工程师》

结语

本人所有博客仅用于学习记录,不做任何商业用途,如涉及侵权,还请联系删除,感谢阅读,欢迎留言,一起进步~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值