Java中锁的概念
自旋锁:为了不放弃CPU执行时间,循环的使用CAS技术对数据进行尝试更新,直至成功。
悲观锁:假定会发生并发冲突,同步所有共享数据的相关操作,从读书据就开始上锁。
乐观锁:假定没有冲突,在修改数据时如果发现数据和之前获取的不一致,则读取最新数据,然后重试修改。
独享锁(写):给资源加上写锁,线程可以修改资源,其它线程不能再加锁;(单写)
共享锁(读):给资源加上读锁后只能读不能改,其他线程也只能加读锁,不能加写锁;(多读)
可重入锁、不可重入锁:线程拿到一把锁之后,可以自由进入同一把锁同步的其他代码,则为可重入锁;否则是不可重入锁。
公平锁、非公平锁:争抢锁的顺序,如果是按先来后到,则为公平锁;否则是非公平锁。
Java中几种重要的锁的实现方式:synchronized、ReentrantLock、ReentrantReadWriteLock
同步关键字synchronized
属于最基本的线程通信机制,基于对象监视器实现的。
Java中的每个对象都与一个监视器相关联,一个线程可以锁定或解锁监视器。
一次只有一个线程可以锁定监视器。
试图锁定该监视器的其他线程都会被阻塞,直到他们可以获得该监视器上的锁定为止。
特性:可重入、独享锁、悲观锁
锁的范围:类锁、对象锁
JVM优化:锁消除、锁粗化
提示:同步关键字,不仅是实现同步,根据JVM规范还能保证可见性(读取最新内存数据,结束后写入主内存)
同步关键字加锁原理:
Java对象头:
如果对象是数组类型,则虚拟机用3个Word(字宽)存储对象头,如果对象是非数组类型,则用2字宽存储对象头。在32位虚拟机中,一字宽等于四字节,即32bit。
运行期Mark World 根据锁的不同状态而可能的存储结构如下图:
对象mark word里面 包含四种状态tag( 00 01 10 11 )
01 无锁 00 轻量锁 10 重量锁 11 GC废弃
同步关键字,优化内容(JDK1.6之后,即锁的升级过程):
1.偏向锁,JVM默认开启,可以使用参数关闭(减少在无竞争情况,JVM资源消耗)
2.出现两个及以上的线程争抢,则升级——>轻量级锁(CAS修改状态)
3.线程CAS自旋一定次数之后,升级为重量级锁(对象的mark word 内部会保存一个监视器锁的一个地址)
锁升级过程示意图如下:
偏向锁示意图:
轻量级锁示意图:
重量级锁示意图:
Monitor构造如下图所示: