synchronized锁

96 阅读2分钟

synchronized 关键字是锁的一种实现

class X {
  // 修饰非静态方法
  // 当修饰非静态方法的时候,锁定的是当前实例对象 this
  synchronized void foo() {
    // 临界区
  }
  // 修饰静态方法 
  // 当修饰静态方法的时候,锁定的是当前类的 Class 对象
  synchronized static void bar() {
    // 临界区
  }
  // 修饰代码块
  Object obj = new Object();
  void baz() {
    synchronized(obj) {
      // 临界区
      // 锁定obj 对象
    }
  }
}  
  • 当修饰非静态方法的时候,锁定的是当前实例对象 this
  • 当修饰静态方法的时候,锁定的是当前类的 Class 对象
  • 当修饰代码块的时候,锁定的是传入的对象

加锁 lock() 和解锁 unlock() 是被 Java 默默加上的,Java 编译器会在 synchronized 修饰的方法或代码块前后自动加上加锁 lock() 和解锁 unlock()

class SafeCalc {
  long value = 0L;
  synchronized long get() {
    return value;
  }
  synchronized void addOne() {
    value += 1;
  }
}

把 value 改成静态变量,把 addOne() 方法改成静态方法

class SafeCalc {
  static long value = 0L;
  synchronized long get() {
    return value;
  }
  synchronized static void addOne() {
    value += 1;
  }
}

改动后的代码是用两个锁保护一个资源。这个受保护的资源就是静态变量 value,两个锁分别是 this 和 SafeCalc.class

由于临界区 get() 和 addOne() 是用两个锁保护的,因此这两个临界区没有互斥关系,临界区 addOne() 对 value 的修改对临界区 get() 也没有可见性保证,这就会导致并发问题了

class SafeCalc {
  long value = 0L;
  long get() {
    synchronized (new Object()) {
      return value;
    }
  }
  void addOne() {
    synchronized (new Object()) {
      value += 1;
    }
  }
}

可以用一把锁来保护多个资源,但是不能用多把锁来保护一个资源

用不同的锁对受保护资源进行精细化管理,能够提升性能。叫细粒度锁

  • 如果资源之间没有关系,很好处理,每个资源一把锁就可以了。
  • 如果资源之间有关联关系,就要选择一个粒度更大的锁,这个锁应该能够覆盖所有相关的资源。

此文章为2月Day15学习笔记,内容来源于学习完极客时间《mysql45讲》后自行拓展,强烈推荐该课程! 开启更多功能,提升办公效能 另外,最近重温操作系统时发现了一个免费精品好课,闪客的《Linux0.11源码趣读》,这个课给我感觉像在用看小说的心态学操作系统源码,写的确实挺牛的,通俗易懂,直指本源,我自己也跟着收获了很多。 这个课在极客时间上是免费的,口碑很不错,看评论下很多人在催更和重温,强烈推荐!

戳此链接领取:time.geekbang.org/opencourse/…

或通过下面海报领取👇🏻!

image.png