Java 如何确保子类'的线程安全;来自超类的方法?
我参加了一次面试,被要求根据以下要求设计一门课程。 假设我有一个类a,它可以有任意数量的子类,即子类。 类A有一个名为doSomething()的方法,该方法是同步的。这些要求是:Java 如何确保子类'的线程安全;来自超类的方法?,java,inheritance,synchronization,Java,Inheritance,Synchronization,我参加了一次面试,被要求根据以下要求设计一门课程。 假设我有一个类a,它可以有任意数量的子类,即子类。 类A有一个名为doSomething()的方法,该方法是同步的。这些要求是: 的所有子类都必须重写doSomething()方法 所有子类重写的doSomething()方法本质上必须是线程安全的 所有子类的doSomething()方法实现都必须有规定来实现自己的逻辑 A类的构造函数由我(设计者)决定如何实现 设计器无法控制将创建多少子类或如何创建子类,即,设计器只能为超类编写代码
我建议将类抽象化,并将doSomething()方法抽象化。这意味着扩展我的类的类必须提供自己的doSomething()方法 然而,我无法回答在我的类A中到底有什么可以确保我的子类的线程安全,而doSomething()方法也是如此 他给出了一个提示,他说这个技巧是在类的构造函数中完成的。
有什么想法吗?经过长时间的研究,我发现如果方法被重写,并且没有在被重写方法的签名中明确添加关键字
synchronized
,那么同步就无法被继承
因为这个问题主要是为了防止其他用户(即开发人员)违反您的类的使用(因为他们正在扩展它)
我想出了一种方法,通过利用Java中的Reflection
类来解决这个问题
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class A {
public A(){
assertSynch("doSomething");
}
// method to assert a particular method is synchronized in the subclass
private void assertSynch(String methodName) {
Class<? extends A> subclass = this.getClass(); // this returns the subclass
Method[] methods = subclass.getDeclaredMethods();
for (Method meth : methods) { // loop through the methods in subclass
if(meth.getName().equals(methodName)) { // when it reaches your method
String modVal = Modifier.toString(meth.getModifiers()); // get its modifier
if(!modVal.contains("synchronized")) { // check if it contains the keyword "synchronized"
try { // if not -> throw an Exception with clear message about the reason and exit
throw new Exception(methodName +
" must be synchronized to ensure class thread safety!");
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
}
}
}
public synchronized void doSomething() {}
}
我认为最好是将base
classdoSomething
方法public final
同步化(final
以确保子类不能重写它),并调用另一个受保护的抽象方法public synchronized final void doSmoething
确保对doSomething
方法的任何调用将是同步的/线程安全的
,doSmoethingImpl
抽象方法将提供灵活性,在子类中给出方法自己的定义
abstract class A {
public synchronized final void doSmoething() {
doSmoethingImpl();
}
protected abstract void doSmoethingImpl();
}
class B extends A {
@Override
protected void doSmoethingImpl() {
// definition in class B
}
}
注意:上述解决方案不会直接满足您的第1点,但dosmotehinginimpl()
将为您提供间接实现类似功能的范围。我没有任何规定为孩子们指定原型。我无法确保子类在其构造函数中调用我的超类构造函数。我只是无法控制孩子们的课堂。另外,我应该将我的超类作为抽象类,将doSomething()也作为抽象类吗?@DukeSensuper()
以任何方式隐式调用!其中,强制所有子类重写doSomething()方法。在您的方法中,它们覆盖了不同的方法,即使它是实现!所有子类重写的doSomething()方法在本质上必须是线程安全的。因为您的doSomething()
是公共的,子类的用户也可以通过重写它来违反它@YahyadoSomething()
无法覆盖,因为它是最终版
。但是doSomethingImpl()
是受保护的abstract
方法,因此任何具体的子类都必须重写doSomethingImpl()
。doSomethingImpl()调用是通过doSomething实现的,因此它将自动实现线程安全(如果您不是直接调用doSomethingImpl的话)。很抱歉,我必须说,实际上您一开始并不理解操作系统的问题!在您的方法中,第一个条件不能肯定地满足,它被标记为强制性。。否则,我们将有更大的空间来考虑正确的方法!不,OP明确提到:一个函数的所有子类都必须重写doSomething()方法,所以它实际上是重写这个方法,而不是用另一个方法来包装它。若OP确实有不同的意思,那个么OP问题的措辞绝对是错误的
abstract class A {
public synchronized final void doSmoething() {
doSmoethingImpl();
}
protected abstract void doSmoethingImpl();
}
class B extends A {
@Override
protected void doSmoethingImpl() {
// definition in class B
}
}