JDK给我们提供了很多种不同的锁,每种锁也会有一些独特的性质 (不包含分布式锁,本篇只介绍java语言锁)
写这篇文章的目的是为了我自己记录,所以有些我很熟悉的知识点我可能就点一下不会深挖。
理解LOCK带着问题找答案
我们先整理出我们想要问的几个问题:
- 锁是什么?(这个和AQS无关)
- 锁会带来什么影响?
- 锁有那些部件?
- 锁过程涉及到那些步骤?
- 什么情况下表示锁住了?
- 什么情况下锁打开?
1. synchronized 关键字
在JDK1.5之前的主流锁,强占锁
针对的目标是对象,只能对引用类型,也就是继承了超类Object的类创建的对象 (注:在使用Integer对象 a 的值 在 -128~127 之间,能够锁住对象,在 a 超出这个范围,并且进行增减 (a++)之后synchronized(a)就会失效,因为integer在超出范围之后会创建新的对象指向 引用 a = new Integer(a+1),这说明synchronized锁的是对象的内容,而不是引用指针)
补充:其实java语言发展到如今,对于synchronized做了非常多的优化了,许多性能方面已经不输其他类型的锁了
2. CAS的了解
在JDK 1.5之后提出了CAS的机制,CAS原理: 利用现代处理器(CPU)都支持的CAS 指令,失败不断重试直至成功。
CAS的优缺点 : 优点-通过处理器指令级别来保证数据的安全,速度上比synchronized要好一些
缺点-相比synchronized
- 开销更大,需要不断检查cas指令是否运行成功 解决:如果JVM能支持处理器提供的pause指令那么效率会有一定的提升
- 导致ABA问题 , 解决:是加版本号
- cas 一个变量能保证原子性,多个变量运算无法保证原子性 解决:将多个变量并成一个or使用atomicStampedReference
在java当中怎么实现呢?
volatile关键字 设置 成员变量 + unsafe类的compareAndSwap方法 前者保证变量的可见性(这里涉及到JMM相关的信息后面会讲) ,后者在CPU级别保证变量不会被重复的修改,是否修改成功通过返回一个Boolean来判定
JDK中相关原子操作类
AtomicBoolean,AtomicInteger,AtomicLong, AtomicIntegerArray,AtomicLongArray
AtomicRefrence ,AtomicReferenceArray , AtomicStampedReference , AtomicMarkbleReference ...
里面的AtomicReference<T> 可以自定义类型,其他有reference同上。
AtomicStampedReference 是带版本号的,上面说的cas的ABA问题就可以通过这个类的方法解决。
3. 关于Current包中Lock的关系图
接下就更具这幅图来品 Doug Lea 给我们带来的并发锁框架 Lock