In Java 8, I can easily write:
interface Interface1 {
default void method1() {
synchronized (this) {
// Something
}
}
static void method2() {
synchronized (Interface1.class) {
// Something
}
}
}
I will get the full synchronisation semantics that I can use also in classes. I cannot, however, use the synchronized
modifier on method declarations:
interface Interface2 {
default synchronized void method1() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
static synchronized void method2() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
}
Now, one can argue that the two interfaces behave the same way except that Interface2
establishes a contract on method1()
and on method2()
, which is a bit stronger than what Interface1
does. Of course, we might also argue that default
implementations should not make any assumptions about concrete implementation state, or that such a keyword simply wouldn't pull its weight.
Question:
What is the reason why the JSR-335 expert group decided not to support synchronized
on interface methods?
虽然起初它似乎很明显是一个将要支持synchronized
的默认方法改性剂,事实证明,这样做会很危险,因此被禁止。
同步方法可用于其中的行为就好像整个主体被封闭在一个方法的速记synchronized
块,其锁定对象为接收端。 这似乎合理的扩展这种语义默认的方法为好; 毕竟,他们是与接收器太实例方法。 (请注意, synchronized
方法是完全句法优化;不是在需要的时候,他们只是比相应的更紧凑的synchronized
。块有被提出,这是摆在首位过早语法优化和合理的说法,同步方法造成更多的问题比解决的,但船舶航行前很长一段时间。)
那么,他们为什么危险? 同步是有关锁定。 锁定为约协调对可变状态的共享访问。 每个对象应该有一个确定哪个锁定护罩,状态变量同步策略。 (见的Java并发实践 ,第2.4节。)
许多对象作为自己的同步策略在Java监视器模式 (JCiP 4.1),其中一个对象的状态由它的内在锁保护使用。 没有什么神奇的或特别的这种模式,但它是方便,而且使用的synchronized
的方法关键字隐含地假定这种模式。
这是拥有该得到确定对象的同步策略的状态类。 但是接口并不拥有到它们在混合对象的状态,所以使用的接口一个synchronized方法假定一个特定的同步策略,而是一个你有假设没有合理的依据,所以它很可能的情况是,使用同步提供无需额外的线程安全任何(可能在错误的锁被同步)。 这会给你的,你已经做了一些关于线程安全的,并且没有错误消息告诉你,你承担了错误的同步策略的信心虚假的安全感。
这已经是够难始终保持为一个单一的源文件同步策略; 就更难保证的子类正确坚持其超类中定义的同步策略。 试图这样松散耦合类(接口和实现它的可能许多类)之间这样做将是几乎不可能和高度容易出错。
鉴于所有这些反对的论点,这将是对论证? 看来他们大多是有关使界面更像特质。 虽然这是一个可以理解的渴望,对默认方法的设计中心是接口的演变,而不是“Traits--”。 其中两个可稳定达到,我们努力这样做,但其中一个是与其他冲突,我们有赞成的主要设计目标来选择。
public class ParentSync {
public synchronized void parentStart() {
System.out.println("I am " + this.getClass() + " . parentStarting. now:" + nowStr());
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I am " + this.getClass() + " . parentFinished. now" + nowStr());
}
private String nowStr() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
}
}
public class SonSync1 extends ParentSync {
public void sonStart() {
System.out.println("I am " + this.getClass() + ". sonStarting,calling parent now ... ");
super.parentStart();
System.out.println("I am " + this.getClass() + ". sonFinished");
}
}
public class SonSync2 extends ParentSync {
public void sonStart() {
System.out.println("I am " + this.getClass() + ". sonStarting,calling parent now ... ");
super.parentStart();
System.out.println("I am " + this.getClass() + ". sonFinished");
}
}
public class SyncTest {
public static void main(String[] args) throws Exception {
new Thread(() -> {
new SonSync1().sonStart();
}).start();
new Thread(() -> {
new SonSync2().sonStart();
}).start();
System.in.read();
}
}
结果:
I am class com.common.interface18_design.whynotsync_onmethod.SonSync1. sonStarting,calling parent now ...
I am class com.common.interface18_design.whynotsync_onmethod.SonSync2. sonStarting,calling parent now ...
I am class com.common.interface18_design.whynotsync_onmethod.SonSync2 . parentStarting. now:2019-04-18 09:50:08
I am class com.common.interface18_design.whynotsync_onmethod.SonSync1 . parentStarting. now:2019-04-18 09:50:08
I am class com.common.interface18_design.whynotsync_onmethod.SonSync1 . parentFinished. now2019-04-18 09:50:38
I am class com.common.interface18_design.whynotsync_onmethod.SonSync1. sonFinished
I am class com.common.interface18_design.whynotsync_onmethod.SonSync2 . parentFinished. now2019-04-18 09:50:38
I am class com.common.interface18_design.whynotsync_onmethod.SonSync2. sonFinished
(抱歉使用父类为例)
从结果中,我们可以知道,父类锁由每个子类资,SonSync1和SonSync2对象有不同的对象锁。 每个锁的独立性。 所以在这种情况下,我认为它使用在父类或一个共同的接口的同步并不危险。 任何人都可以更多地解释这个?
文章来源: What is the reason why “synchronized” is not allowed in Java 8 interface methods?