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 (共享锁)状态需要向后传播