@Synchronized
synchronized 的正确用法:不要暴露你的锁。
概述
@Synchronized 是 synchronized 方法修饰符更安全的变体。与 synchronized 类似,此注解只能用于静态方法和实例方法。它的运作方式与 synchronized 关键字类似,但它锁定在不同的对象上。关键字锁定在 this 上,而注解锁定在名为 $lock 的私有字段上。
如果该字段不存在,则会自动为你创建。如果你注解的是 static 方法,则注解会锁定在名为 $LOCK 的静态字段上。
如果需要,你可以自己创建这些锁。如果你已经自己创建了 $lock 和 $LOCK 字段,当然就不会再生成它们。你也可以选择锁定在另一个字段上,方法是将该字段指定为 @Synchronized 注解的参数。在这种用法变体中,字段不会自动创建,你必须显式地自己创建它们,否则会发出错误。
锁定在 this 或你自己的类对象上可能会产生不幸的副作用,因为不受你控制的其他代码也可以锁定在这些对象上,这可能会导致竞态条件和其他与线程相关的讨厌的错误。
如果你更喜欢 java.util.concurrent.locks 风格的锁(如果你正在使用虚拟线程,则推荐使用),请查看 @Locked。
使用 Lombok
import lombok.Synchronized;
|
原生 Java
public class SynchronizedExample {
|
支持的配置键
-
lombok.synchronized.flagUsage= [warning|error] (默认值:未设置) - 如果配置了,Lombok 将把任何
@Synchronized的用法标记为警告或错误。
小字说明
如果 $lock 和/或 $LOCK 是自动生成的,则这些字段将使用空的 Object[] 数组初始化,而不是像大多数展示这种模式的片段那样,仅仅使用 new Object()。 Lombok 这样做是因为新的对象是 *不可* 序列化的,但 0 大小的数组是可序列化的。因此,使用 @Synchronized 不会阻止你的对象被序列化。
在你的类中至少有一个 @Synchronized 方法意味着会有一个锁字段,但如果你稍后删除所有此类方法,将不再有锁字段。这意味着你预定的 serialVersionUID 会发生变化。我们建议你,如果你打算通过 Java 的序列化机制长期存储你的类, *始终* 为你的类添加 serialVersionUID。如果你这样做,从你的方法中删除所有 @Synchronized 注解将不会破坏序列化。
如果你想知道为什么当你为你自己的锁对象选择自己的名称时,字段不会自动生成:因为否则在字段名称中出现拼写错误将导致一个 *非常* 难以发现的错误!