Skip to content

@Synchronized

YellowStar5 edited this page Aug 2, 2019 · 1 revision

@Synchronized

synchronized 做了正确的事:不要暴露你的锁。

概览

@Synchronizedsynchronized 方法修饰符的更安全的变体。与 synchronized 类似,该注释只能用于静态和实例方法。它的操作类似于 synchronized 关键字,但它锁定在不同的对象上。synchronized 关键字在 this 锁定,但注解锁定在名为 $lock 的私有字段上。

如果该字段不存在,lombok 则会为你创建该字段。如果注释 一个 static 方法,则注解会锁定名为 $LOCK 的静态字段。

如果需要,你可以自己创建这些锁。如果你已经自己创建了 $lock$LOCK 字段,那么lombok当然不会生成他们。你还可以选择锁定另一个字段,方法是将其指定为 @Synchronized 注解的参数。在此用法变体中,不会自动创建字段,你必须自己显式创建它们,否则将发出错误。

锁定 this 或你自己的类对象会产生不幸的副作用,因为不受你控制的其他代码也可以锁定这些对象,这可能会导致竞争条件和其他讨厌的线程相关的错误.

With lombok

import lombok.Synchronized;
public class SynchronizedExample {
  private final Object readLock = new Object();
  
  @Synchronized
  public static void hello() {
    System.out.println("world");
  }
  
  @Synchronized
  public int answerToLife() {
    return 42;
  }
  
  @Synchronized("readLock")
  public void foo() {
    System.out.println("bar");
  }
}

Vanilla Java

public class SynchronizedExample {
  private static final Object $LOCK = new Object[0];
  private final Object $lock = new Object[0];
  private final Object readLock = new Object();
  
  public static void hello() {
    synchronized($LOCK) {
      System.out.println("world");
    }
  }
  
  public int answerToLife() {
    synchronized($lock) {
      return 42;
    }
  }
  
  public void foo() {
    synchronized(readLock) {
      System.out.println("bar");
    }
  }
}

支持的配置键

lombok.synchronized.flagUsage = [ warning | error ](默认:未设置) 如果已配置,Lombok 会将 @Synchronized 的任何用法标记为警告或错误。

Small print

如果自动生成 $lock 和/或 $LOCK ,则使用空的 Object[]数组初始化字段,而不仅仅是一个 new Object() ,正如大多数片段在操作中显示此模式。 Lombok 这样做是因为new Object() 不可序列化,但是大小为0的数组可以序列化。因此,使用 @Synchronized 不会阻止对象序列化。

在类中至少有一个 @Synchronized 方法意味着会有一个锁定字段,但是如果稍后删除所有这些方法,则不再有锁定字段。这意味着你预定的 serialVersionUID 会发生变化。如果你打算通过java的序列化机制长期存储它们,我们建议您始终在你的类中添加 serialVersionUID 。如果这样做,从方法中删除所有 @Synchronized 注解将不会破坏序列化。

如果你想知道为什么在为锁定对象选择自己的名称时不会自动生成字段:因为如果这么做了,在字段名称中输入错误将导致很难找到错误!