为什么"synchronized"对多态没有作用
Why "synchronized" has no role in polymorphism
synchronized
不是方法签名的一部分。但是当我们覆盖一个方法时,决定被覆盖的方法是否编译的不仅仅是方法签名。
例如,我们不能添加或扩大检查异常
为什么synchronized
对多态没有作用。如果不放置 synchronized
,则不应覆盖 synchronized
方法。因为使用 super class 变量的人可能认为所有方法都是线程安全的。
但是应该允许使用 synchronized
覆盖非同步方法,因为它添加了更多功能,但另一方面用户不会遇到任何错误,除了时间延迟。
我正在寻找一个合乎逻辑的解释,它可以为 "why is designed so" 提供一些线索。
A "synchronized" method should not be overridden without putting "synchronized".
错了。 base class 可能不是线程安全的,但是 subclass 可能有自己的同步,例如锁,无锁线程安全数据结构等。不是所有线程安全的方法都是同步的,并不是所有的同步方法都是线程安全的。
反之亦然(但可能会违反其他原则,视情况而定)
synchronized
不是面向对象的东西,而是 runtime/execution 现象和实现细节。它所做的只是 acquire a monitor 与 synchronized(this){ }
相同的方式(或者在 java.lang.Class 对象上同步,如果是静态的)。作为实现细节,将其暴露给 OOP 考虑是没有意义的。
注意:这并不意味着 @ThreadSafe
之类的编译时注释没有意义。它确实如此,因为它引用方法的契约是线程安全的。 synchronized
不会这样做。
您可以看到 JDK-4294756 的解释,一个方法可以在不保留 synchronized
修饰符的情况下覆盖另一个方法。此错误报告要求编译器在方法重写 synchronized
方法但未声明自身 synchronized
时显示警告,并作为 "Won't Fix" 关闭。关键原因如下:
The use of the synchronized modifier, as well as other synchronization via
explicit 'synchronized' statements, is a part of the implementation of an
abstraction represented by a class, and an alternate implementation captured
in a subclass may use a different synchronization strategy in order to
implement equivalent semantics. As an example, consider the case in which a
small critical section (protected by a 'synchronized' statement) within a larger
unsynchronized method replaces a smaller method that was protected in its
entirety by a synchronized method modifier.
因此缺少 synchronized
修饰符并不一定意味着该方法不是线程安全的。线程安全可以在方法内部细化。
让我换一种说法:
假设我们有两个 classes:
class Foo {
public synchronized void doSomething(...) { ... }
}
class Bar extends Foo {
public void doSomething(...) { ... }
}
Foo
和 Bar
不同 class。 foo.doSomething(...)
和 bar.doSomething(...)
是不同的方法。
synchronized
关键字不是为了调用者的利益而存在的:它没有说明 foo.doSomething(...)
做什么 。 synchronized
关键字只是该方法如何 实现 .
的详细信息
Foo
class 需要同步其 doSomething(...)
方法,以便在多线程环境中正确履行其 API 契约。 bar.doSomething(...)
方法的实现方式不同,不需要同步。
只要 Bar
实例可以用在任何需要 Foo
实例的地方,每个人都应该高兴。调用者没有理由希望方法同步:调用者应该只希望方法 work.
synchronized
不是方法签名的一部分。但是当我们覆盖一个方法时,决定被覆盖的方法是否编译的不仅仅是方法签名。
例如,我们不能添加或扩大检查异常
为什么synchronized
对多态没有作用。如果不放置 synchronized
,则不应覆盖 synchronized
方法。因为使用 super class 变量的人可能认为所有方法都是线程安全的。
但是应该允许使用 synchronized
覆盖非同步方法,因为它添加了更多功能,但另一方面用户不会遇到任何错误,除了时间延迟。
我正在寻找一个合乎逻辑的解释,它可以为 "why is designed so" 提供一些线索。
A "synchronized" method should not be overridden without putting "synchronized".
错了。 base class 可能不是线程安全的,但是 subclass 可能有自己的同步,例如锁,无锁线程安全数据结构等。不是所有线程安全的方法都是同步的,并不是所有的同步方法都是线程安全的。
反之亦然(但可能会违反其他原则,视情况而定)
synchronized
不是面向对象的东西,而是 runtime/execution 现象和实现细节。它所做的只是 acquire a monitor 与 synchronized(this){ }
相同的方式(或者在 java.lang.Class 对象上同步,如果是静态的)。作为实现细节,将其暴露给 OOP 考虑是没有意义的。
注意:这并不意味着 @ThreadSafe
之类的编译时注释没有意义。它确实如此,因为它引用方法的契约是线程安全的。 synchronized
不会这样做。
您可以看到 JDK-4294756 的解释,一个方法可以在不保留 synchronized
修饰符的情况下覆盖另一个方法。此错误报告要求编译器在方法重写 synchronized
方法但未声明自身 synchronized
时显示警告,并作为 "Won't Fix" 关闭。关键原因如下:
The use of the synchronized modifier, as well as other synchronization via explicit 'synchronized' statements, is a part of the implementation of an abstraction represented by a class, and an alternate implementation captured in a subclass may use a different synchronization strategy in order to implement equivalent semantics. As an example, consider the case in which a small critical section (protected by a 'synchronized' statement) within a larger unsynchronized method replaces a smaller method that was protected in its entirety by a synchronized method modifier.
因此缺少 synchronized
修饰符并不一定意味着该方法不是线程安全的。线程安全可以在方法内部细化。
让我换一种说法:
假设我们有两个 classes:
class Foo {
public synchronized void doSomething(...) { ... }
}
class Bar extends Foo {
public void doSomething(...) { ... }
}
Foo
和 Bar
不同 class。 foo.doSomething(...)
和 bar.doSomething(...)
是不同的方法。
synchronized
关键字不是为了调用者的利益而存在的:它没有说明 foo.doSomething(...)
做什么 。 synchronized
关键字只是该方法如何 实现 .
Foo
class 需要同步其 doSomething(...)
方法,以便在多线程环境中正确履行其 API 契约。 bar.doSomething(...)
方法的实现方式不同,不需要同步。
只要 Bar
实例可以用在任何需要 Foo
实例的地方,每个人都应该高兴。调用者没有理由希望方法同步:调用者应该只希望方法 work.