你不知道的锁

169 阅读3分钟

synchronized(关键字)

锁是存放在对象头

java对象包含三个部分

对象头-实例数据-填充字节(满足对象大小=8 bit *n)

对象头包含两部分(Mark work和 class point )

class point 是一个指针,指向当前对象类型所在方法区中的类型数据

mark word(只有32 bit) 存储了很多和当前对象运行时状态有关的数据:

最重要是的是是否是偏向锁(1 bit),锁标志位(2bit)

是否偏向锁 锁标志位

无锁 0 01

偏向锁 1 01

轻量级锁 00

重量级锁 10

synchronized 中 javac 获得字节码指令

monitor(管程/监视器) 依赖操作系统(mutex locak 导致性能低下) 比较重量级

monitorenter

monitorexit

无锁:

偏向锁:只要有线程过来,就把锁交出去。判断是否判是偏向锁,1bit 2bit。

判断是否该交出去,获取mark word前 23位线程id,与当前线程是否相同。

发现不只有一个线程,变成轻量级锁

轻量级锁:前30bit 变为指向栈中锁记录的指针。

在虚拟机栈中开辟一块被称为lock record的空间,存放对象头中Mard word副本。

将locak record中的owner指针指向该对象

对象的mark work 前30bit生成一个指针,指向线程虚拟机栈的lock record。

实现线程和对象锁的绑定

再次进来时,其他线程会自旋轮询()

一旦自旋等待的线程数超过一个,变为重量级锁

重量级锁:通过monitor 来对线程进行控制,完全锁定资源。

乐观锁(无锁同步机制):cas,获取当前版本号,比较,相同更新,不相同自旋。必须是原子性的

优点:

lock (接口)

AQS:

核心:AbstractQueueSynchronizer 抽象队列同步器,用来实现锁的基础

1.RenntrantLock 可重入锁,独占模式

2.Semaphore

3.RenntrantReadWriteLock 独占模式和共享模式

...

独占模式分为公平锁和非公平锁:

公平锁: 按照线程在队列中的排队顺序,先到者先拿到锁

非公平锁:线程要获取锁时,无视队列顺序直接去抢锁,谁抢到就是谁的,非公平锁效率高

使用cas进行同步,必须是原子操作

内部核心变量:

state,int类型,volatile(保证内存可见性),代表加锁状态 state值默认是0,表示锁未被占用

加锁线程 用来记录当前加锁的是哪个线程,默认是null

同步队列:RenntrantLock

等待队列:使用condition时出现。

①调用lock() 使用AQS将state 变为 1

②加锁成功,设置加锁线程 == 当前线程

③可重入锁,线程2进行先看state是否为0,再看是否为1,如果为1,查看加锁线程是否是

自己,是自己的话加锁成功,不是自己加锁失败。

④加锁失败了,会放至在等待队列中。

⑤如果state变为0,则将等待队列中的对头唤醒进行尝试加锁。

waitStatus(等待状态)

CANCLELLED = 1 线程被取消

SIGNAL = -1 释放资源后需唤醒后继节节点

CONDITION = -2 等待condition唤醒

PROPAGATE = -3 (共享锁)状态需要向后传播