自旋锁:为了不放弃CPU执行事件,循环的使用ACS技术对数据尝试进行更新,直至成功。
悲观锁:假定会发生并发冲突,同步所有对数据的相关操作,从读数据就开始上锁。
乐观锁:假定没有冲突,在修改数据时如果发现数据和之前获取的不一致,则读最新数据,修改为最新后重新修改数据。
独享锁(写):给资源加上写锁,线程可以修改资源,其他线程不能再加锁。(单个线程写)
共享锁(读):给资源加上读锁后只能读不能改,其他线程也只能加读锁,不能加写锁;(多读)。
可重入锁、不可重入锁:线程拿到一把锁之后,可以自由进入同一把锁所同步的其他代码。
公平锁、非公平锁:争抢锁的顺序,如果是按先来后到,则为公平。
几种锁的重要实现:Synchronized 、ReentrantLock、 ReentrantReadWriteLock
同步关键字Synchronized
属于最基本的线程通信机制,基于对象监视器实现。
Java中的每个对象都与一个监视器相关联,一个线程可以锁定和解锁。
一次只有一个线程可以锁定监视器。
试图锁定修改监视器的任何线程都会被阻塞,直到它们可以获得该监视器上的锁定为止。
特性:可重入、独享、悲观锁。
锁的范围:类锁、对象锁、锁消除、锁粗化。
提示:同步关键字,不仅是实现同步,根据JVM规定还能保证可见性(读取最新主内存数据,结束后写入主内存)。
同步关键字加锁原理:
HotSpot中,对象前面会有一个类指针和标题,存储标识哈希码的标题以及用于分代垃圾收集的年龄和标记位。
轻量级加锁:直接改变一个对象的头信息, 修改轻量级锁内容,锁状态
使用CAS修改mark Word完毕,加锁成功。则mark work中的tag进入00 状态。
解锁的过程,则是一个逆向恢复mark word的过程。
默认情况下JVM会经历:偏向锁->轻量级锁->重量级锁这四个状态。
Tag锁状态标志:00:无锁、01轻量级锁CAS、10:重量级锁、监视器锁、11:GC
偏向锁到轻量级锁:
偏向锁: 对象头信息中有个是否开启偏向,并且记录线程ID,当只有一个线程使用并判断是否加锁,就会记录这个线程的id。后续这个线程再次访问,直接判断线程id即可。再次有个线程访问该对象,则偏向锁升级为轻量级锁
偏向标记第一次有用,出现过争抢后就没用了。 -XX: UserBiasedLocking 禁用使用偏置锁定。
偏向锁,本质就是无锁,如果没有发生过任何多线程争抢锁的情况,,JVM认为就是单线程,无需做同步(JVM就是为了少干活:同步在JVM底层是有很多操作来实现的,如果没出现争抢,就不需要去做同步操作)
同步关键字加锁原理- 轻量级锁:
使用CAS修改mark word完毕,加锁成功。则mark word中的tag进入00状态。解锁过程,则是一个逆向恢复mark woed的过程。
重量级锁 - 监视器(monitor)
修改mark word失败,会自旋CAS一定次数,该次数可以通过参数配置:超过次数,仍未抢到锁,则锁升级为重量级锁,进入阻塞。
Monitor也叫做管程,计算机操作系统原理中有提及类似概念。一个对象会有一个对应的monitor。