Java内置锁synchronized

时间:2021-09-06 03:17:57   收藏:0   阅读:23

Java中锁是比较难的一块,包括synchronized,如加锁之后对象头信息的变化是怎样的?更不用说AQS。不要一开始就纠结共享锁/独占锁,公平锁/非公平锁,以及偏向等,应该从原理层面去理解,一劳永逸。

Synchronized

在JDK1.6之前,synchronized重度依赖于操作系统,涉及到CPU状态切换,效率很低。(据说Doug Lea因此才开发了AQS框架)。JDK1.6才有了较大的优化,引入了锁的膨胀升级机制。

查看对象头信息的工具:

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.16</version>
</dependency>

32位虚拟机对象头组成参考:
技术分享图片

synchronized的用法

  1. 修饰指定对象
// 锁住的只是obj这个对象
Object obj = new Object();

synchronized (obj) {
  System.out.println("...");

  // synchronized是可重入的, 这里实际上会被优化掉
  synchronized (obj) {
    System.out.println("***");
  }
}
  1. 修饰普通方法
// 锁住的是具体的实例
public class Test {
  public synchronized void print() {
    System.out.println("...");
  }
}
  1. 修饰静态方法
// 锁住的是当前类,静态成员属于类
public class Test {
  public static synchronized void print() {
    System.out.println("...");
  }
}

synchronized的升级过程

锁的升级过程是不可逆的。偏向锁不是真正加锁,偏向锁和无锁状态是可以转换的。另外,调用hashCode()会导致锁升级,无法重新进入偏向状态,涉及对象头的结构,很复杂。

synchronized的粗化

Object obj = new Object();

synchronized (obj) {
  synchronized (obj) {
    System.out.println("***");
  }
}

这样加锁代码可以执行,但实际上里层的synchronized是完全不必要的,只需留下外层的synchronized即可,而JVM就会做这种优化,即锁的粗化。

synchronized的消除

Object obj = new Object();

synchronized (obj) {
  synchronized (obj) {
    System.out.println("***");
  }
}

如果本身程序就是单线程的,不需要锁,JVM也会优化,将锁去掉,即锁的消除。实际上粗话就消除了里层的锁。

由上述内容可以得知,synchronized是可重入锁。另外,多个线程来synchronized(obj)的时候,synchronized无法对线程进行排队,而是线程去抢,所以是非公平的。

原文:https://www.cnblogs.com/farwalking/p/15229053.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!