锁的基本概念
保护临界区资源不会被多个线程同时访问时而受到破坏。通过锁,可以让多个线程排队。一个一个地进入临界区访问目标对象,使目标对象的状态总是保持一致。
线程安全
无论多个线程如何访问目标对象,目标对象的状态始终保持一致,线程的行为也总是正确的,这说明线程是安全的。
1.关键字Synchronized保证每次只有一个线程访问实例,确保多线程中对象内部数据的一致性。
对象头和锁
在Java虚拟机的实现中,每个对象都有一个对象头,用于保存对象的系统信息,对象头中有一个称为Mark Word的部分,它是实现锁的关键,存放对象的哈希值、对象年龄、锁的指针等信息。
一个对象是否占用锁,占用哪个锁就记录在这个Mark Word.
偏向锁
如果程序没有竞争,则取消之前已经取得锁的线程同步操作。也就是说,若某一锁被线程获取后,便进入偏向模式,当线程再次请求这个锁时,无需再进行相关的同步操作,节省了操作时间。如果在此之前其他线程请求了锁,则锁退出偏向模式。
轻量级锁
如果偏向锁失败,Java虚拟机会让线程申请轻量级锁
当需要判断某一线程是否持有该对象锁时,也只需简单地判断对象头的指针是否在当前线程的栈地址范围即可。
膨胀锁
当轻量级锁失败,虚拟机就会使用重量级锁。
自旋锁
自旋锁可以使线程在没有取得锁时,不被挂起,而转而去执行一个空循环,在若干个循环后,线程如果可以获得锁,则继续执行,若线程依然不能获得锁,才会被挂起。
锁消除
Java虚拟机在JIT编译时,通过对运行上下文的扫描,去除不可能存在共享资源的竞争的锁。通过锁消除,可以节省毫无意义的请求锁时间。