浅谈synchronized


一、synchronized的作用

synchronized可以给方法和代码块加锁,保证该方法或者该断代码块同一时间智能有同一个线程访问,从而避免了线程安全问题。

二、synchronized中的几种状态

被synchronized加锁的对象中会有五种状态:

  • 0(00):轻量级锁状态,该状态下的线程只会进行膨胀,而不会进行自旋,更不会使用到monitor进行从用户态到内核态的重量级转换操作;
  • 1(001):无锁状态,jdk1.6之后,对象创建出来的前4s内都是无锁状态,4s后如果没有线程使用,那么会将该对象置为匿名偏向锁状态;
  • 2(10):重量级锁状态,线程在该状态下会进行自旋,如果多次自旋未获取到锁则会使用到monitor,进行从用户态到内核态的重量级转换操作;
  • 3(11):gc状态,表明当前对象已被垃圾回收器标记,马上就会被回收;
  • 5(101):偏向锁状态,jdk1.6之后默认所有对象都是匿名偏向锁状态,不过该状态要在4s后才会生效。当第一个线程访问该对象的时候,该对象才会改变为指向偏向锁状态;

三、synchronized的锁升级原理

  • 当线程第一次访问该对象时,当前对象的对象头里面会有一个ThreadId属性来保存当前访问对象的ID,并且会将此时的锁状态调整为偏向锁状态(无锁状态的时候会调整,偏向锁状态的情况下只会写入线程ID)。
  • 当第二次有线程来访问该对象时,会先对比ThreadId来判断是否是之前第一次访问的线程,如果是的话就可以直接访问到该对象,如果不是则会进行自旋,并将该对象的偏向锁升级为轻量级锁。
  • 当某个线程自旋一定时间后仍旧没有获取到锁无法访问对象的话,它就会使用到monitor进入到队列中,并将对象的锁置为重量级锁状态,等待被唤醒。

四、锁升/降级的注意点

锁升级可以一级一级的递增,但是锁降级只能先降至最低的无锁状态才能转换为其它的状态

五、偏向锁撤销

偏向锁由于解锁后仍旧是偏向锁,所以引出了一个新的概念:偏向锁撤销

  • 如果是匿名偏向锁,撤销后将会变为无锁状态;
  • 如果是绑定线程(指向)的偏向锁,撤销后则会升级为轻量级锁;
  • 如果是绑定线程(指向)的偏向锁并且同步代码块种调用了hashcode或者wait方法,撤销后则会升级为重量级锁;

六、synchronized修饰静态方法、普通方法的区别

synchronized修饰静态方法表明该锁是一个类锁,哪怕是不同的对象,该把锁也需要线程去竞争;
synchronized修饰普通方法表明该锁是一个对象锁,这种情况下不同对象之间的锁是不共享的,也即是两个对象之间的属性数据不能保持同步;

具体的使用可参考:synchronized 修饰静态方法、普通方法与代码块的区别

猜你喜欢

转载自blog.csdn.net/qq_42697271/article/details/121271051