使用同步(锁定对象)块时,静态锁定对象是否需要是最终的?

Does a static lock object need to be final when using a synchronized(lock object) block?

假设我有一个

private static Object lock = new Object();

和同一个地方class

public void run() {
synchronized(lock) {
    //only 1 thread here, all others wait
  }
}

我总是读到锁对象应该是最终的,但不完全是为什么。 假设我 100% 知道我的代码不会在任何地方触及锁定对象, 如果省略了 final 关键字,这是否意味着同步不是 100% 防弹

如果没有您所依赖的 final 修饰符,但是对象已被初始化以使其正确可见,并假设没有任何改变其值。由于它是静态的,因此在加载 class 时会发生初始化并且存在可见性保证,因此从技术上讲,您可以将其保留为非最终状态。 (虽然代码使用同步块,但当然在进入块之前必须评估正在使用的锁。)

如果锁定对象在使用时被更改为另一个,那么两个线程可能处于同一段受保护代码中,整个锁定方案就会受到损害。在此处添加 final 关键字意味着编译器正在帮助您确保此锁不会更改,如果有人稍后尝试更改它,将导致编译错误。

从编译器那里获得尽可能多的帮助通常是一件好事,并且编译会告诉你该字段是否已更改,因此这是一个低风险的更改,可以确保一个大的问题不可能发生。

在此上下文中使用 final 只是一种很好的做法。

您可以使用任何对象进行同步,final 或非最终对象,static 或非静态对象。

一起使用 finalstatic 将为您提供安全性,因为没有人会在不同的锁上同步相同的代码。如果不使用 final,您不确定代码中某处是否未重新分配该变量。

一般来说,对一个在初始化后永远不会重新分配的变量使用 final 是一个很好的编程习惯。它提高了可读性,因为阅读你的代码的人都知道,如果不阅读完整的代码,这个变量也永远不会被重新分配。