无锁状态:
为了保证获得锁和释放锁的效率,锁可以升级但不能降级。
举例: 开门;
偏向锁:当第一个线程开门,对该门贴个标签(自己专用),下次进出方便。(标签是线程id)
轻量级锁:当另一个线程也要开门时,首先撕掉标签,两个线程竞争,在自己的栈帧中创建一个lockrecord,查看门上贴的是哪一个标签,如果不是自己,采用自旋的方式,如果在贴自己标签时,门上的标签原始值一样,则让门上的标签指向自己的lockrecord,否则继续进行自旋操作。(标签是指向锁记录)
重量级锁:当自旋数达到10次或者自旋的线程数超过cpu核心数的一半时,升级为重量级锁。
偏向锁
- 当第一个线程对同步块进行加锁时,进行cas操作,在对象头和栈帧中的锁记录里存储锁偏向的线程id,以后在该线程进入或者退出该同步块时不需要进行cas操作。
- 偏向锁的撤销:当出现另一个线程竞争该锁时,会撤销该锁。
- 优点:加锁和解锁不需要进行额外的操作,执行速度快。
- 缺点:如果线程存在锁竞争,会带来额外的锁撤销的消耗。
- 适用场景:只有一个线程访问同步块
轻量级锁
- 线程在执行同步块时,会在栈帧中创建一个存储锁记录的空间,并将对象头中的markword复制到锁记录中,然后线程尝试进行cas操作,让对象的markword的指针指向锁记录。如果失败则重新进行自旋操作。
- 锁撤销:当自旋数达到10次或者自旋的线程数超过cpu核心数的一半时。
- 优点:竞争的线程不会阻塞,提高了响应速度。
- 缺点:如果始终得不到锁竞争的线程,大量消耗cpu
- 适用场景:追求响应时间,同步块执行速度快
重量级锁
- 从用户态切换到内核态,把要获得锁的线程放入到队列中,依次进行,不占用cpu.
- 依赖对象内部的monitor锁来实现的,而monitor又依赖操作系统的MutexLock(互斥锁)来实现的.
- 优点:线程竞争不使用自旋,不消耗cpu。
- 缺点:线程阻塞,响应时间慢
- 适用场景:追求吞吐量,同步代码块执行时间长。
- 为什么重量级线程开销很大的?
当系统检查到锁是重量级锁之后,会把等待想要获得锁的线程进行阻塞,被阻塞的线程不会消耗cpu。但是阻塞或者唤醒一个线程时,都需要操作系统来帮忙,这就需要从用户态转换到内核态,而转换状态是需要消耗很多时间的,有可能比用户执行代码的时间还要长。
32位操作系统