java-锁得升级(概念):偏向锁--轻量级锁--重量级锁

偏向锁:

  • 在大多数情况下,锁不仅仅不存在多线程的竞争,而且总是由同一个线程多次获得。在这个背景下就设计了偏向锁。偏向锁,顾名思义,就是锁偏向于某个线程。
  • 当一个线程访问加了同步锁的代码块时,会在对象头中存储当前线程的ID,后续这个线程进入和退出这段加了同步锁的代码块时,不需要再次加锁和释放锁。而是直接比较对象头里面是否存储了指向当前线程的偏向锁。如果相等表示偏向锁是偏向于当前线程的,就不需要再尝试获得锁了,引入偏向锁是为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行路径。(偏向锁的目的是消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。)

轻量级锁

如果偏向锁被关闭或者当前偏向锁已经已经被其他线程获取,那么这个时候如果有线程去抢占同步锁时,锁会升级到轻量级锁。

重量级锁

  • 如果当前为轻量级锁,当前线程去抢占锁但是发现锁已经被占用,那他会进入自旋(重试),1.6以前默认自旋10次,如果还是没有获取到锁,那他会升级膨胀,升级到重量级锁并阻塞;(注:1.6之后 自适应自旋锁:会根据上一次抢占时间去决定当前抢占随时间的长短,如果上一次自旋时间很长,那这次就短,如果上次短,那这次就长一些)。
  • 多个线程竞争同一个锁的时候,虚拟机会阻塞加锁失败的线程,并且在目标锁被释放的时候,唤醒这些线程;
  • Java 线程的阻塞以及唤醒,都是依靠操作系统来完成的:os pthread_mutex_lock() ;
  • 升级为重量级锁时,锁标志的状态值变为“10”,此时Mark Word中存储的是指向重量级锁的指针,此时等待锁的线程都会进入阻塞状态

整理:

  • 偏向锁只有在第一次请求时采用CAS在锁对象的标记中记录当前线程的地址,在之后该线程再次进入同步代码块时,不需要抢占锁,直接判断线程ID即可,这种适用于锁会被同一个线程多次抢占的情况。
  • 轻量级锁才用CAS操作,把锁对象的标记字段替换为一个指针指向当前线程栈帧中的LockRecord,该工件存储锁对象原本的标记字段,它针对的是多个线程在不同时间段内申请通一把锁的情况。
  • 重量级锁会阻塞、和唤醒加锁的线程,它适用于多个线程同时竞争同一把锁的情况。

 

你可能感兴趣的:(安全,java,锁,java)