synchronized锁

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;
    }
  }
}

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

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

  • 如果资源之间没有关系,很好处理,每个资源一把锁就可以了。
  • 如果资源之间有关联关系,就要选择一个粒度更大的锁,这个锁应该能够覆盖所有相关的资源。
posted @ 2022-05-05 16:59  请务必优秀  阅读(88)  评论(0)    收藏  举报