java轻量级锁、重量级锁、可重入锁、偏向锁、自旋锁的概念
1、重量级锁
作为互斥同步的方式,是最基础的锁,其他的锁都是为了减少开销做的优化,重量级锁借助了monitor 对象,monitor对象中有三个区域,分别是entity site、 owner和wait,进程进入同步前首先进入entity区域等待,若owner没有进程,则进入owner区域,若owner区域已经有进程则阻塞等待,owner也可以执行wait进入wait区域,当owner区域的进程执行完毕释放锁后,会唤醒阻塞的进程竞争锁,由于会导致线程的阻塞,则势必会导致用户态到核心态的切换,大大增加了损耗,因此才称为重量级锁。
2、自旋锁
自旋锁就是为了防止线程阻塞所带来的上下文切换损耗,当线程竞争锁失败后,并不阻塞,而是继续请求锁直到锁释放,一般虚拟机设置为10次,可以自己设置,现在虚拟机也可以根据对象使用动态设置,当然自旋过程中也需要占用cpu,因此只使用于多核心的情况下,类似于等红灯的时候不熄火等绿灯。
3、轻量级锁
轻量级锁是在线程没有其他竞争者的情况下的操作,先说一下对象头的构造,对象头的一部分存储的是与对象自身信息无关的信息,被称为markword,包括自身hash码、gc分代年龄等,mark word的32个比特里25个比特存哈希码,4个存分代年龄,2个存锁标记,1个存是否进入偏向锁,当对象被加了轻量级锁后,markword就被拷贝到当前线程空间的Lock record,并被替换成指向Lock record的指针,替换过程要采用CAS操作。如果更新失败则说明有线程在竞争当前对象,将锁膨胀成为重量级锁,在解锁时同样要进行CAS操作进行修改,如果失败则说明当前锁已经进入重量级锁,要唤醒等待进程,假如进程A持有当前锁对象,而此时进程B试图获取,则B会将锁修改为重量级锁,虚拟机会建立monitor对象,B进入阻塞或者自旋。
4、偏向锁
偏向锁和轻量级锁一样,都是基于当前进程没有其他进程竞争锁对象时,偏向锁更加乐观,偏向锁会将对象头的偏向模式置为1,与轻量级锁不同的是,对象头的markword区域存放的是当前占用锁对象的线程的线程id,这个时候会引发一个问题,就是原本markword存放的是对象的hashcode,也就是一致性哈希码,java语言中当一个对象计算过hash码后就将其存放在对象头中,并且应当保持不变,因此如果一个对象已经计算过hash码后,就不能使用偏向锁。当线程确定当前锁对象是自身后,则不进行CAS操作,直接继续使用对象,除非有其他进程竞争才膨胀为重量级锁。
5、可重入锁
当前进程在获取锁对象后,第二次获取对象时若持有锁对象的是自身,则可以继续使用,底层源于AQS机制,会维护一个state,可重入锁为:一个线程试图获取一个共享资源时,若当前资源的state为0,则置为1,锁定当前共享资源,若不为0,则检查持有者是否为本身,若为本身则继续将state+1,不是则阻塞,当使用完共享资源后也会将state-1,直到state为0时才释放资源,不可重入锁的意思是:一个线程试图获取一个共享资源时,若当前资源的state为0,则置为1,锁定当前共享资源,若不为0,则不会检查,直接陷入阻塞等待,当使用完后直接释放锁对象。
在锁优化中,若无其他线程竞争锁对象,当有使用到当前锁对象的hashcode时,也会导致锁膨胀
浙公网安备 33010602011771号