问题
I attended an interview and I was asked to design a class for the following requirement. Assume I have a class A and it can have any number of children, i.e., subclasses. The class A has a method called doSomething() which is synchronized. The requirements are :
- It is mandatory that all subclasses of A override the doSomething() method.
- All subclasses' overriden doSomething() method must be Thread safe in nature.
- All subclasses' must have the provision to implement their own logic for their doSomething() method implementations.
Class A's constructor is upto me(the designer) to decide how to implement.
The designer has no control on how many subclasses would be created or how they would be created,i.e., the designer can only write code for the superclass only.
I suggested to make the class abstract and also the doSomething() method abstract. This would imply classes extending my class necessarily provide their own doSomething() method.
However, I could not answer as to what exactly in my class A would ensure Thread safety for my child classes and that too just for the doSomething() method.
He gave a hint though, he said the trick is to be done in A class' constructor.
Any ideas?
回答1:
After a very long research I found out that synchronization
cannot be inherited if the method is overridden and without explicitly adding the keyword synchronized
in the the overridden method's signature!!
And because this issue is mainly addressed to prevent other users (i.e. developers) from violating the use of your class (as they are extending it).
I came up with a way to work around it by availing of the Reflection
class in Java.
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() {}
}
public class B extends A{
public B() { } // it implicitly calls the superclass constructor
@Override
public void doSomething() { } // it will make the program to throw the above exception
}
回答2:
I would say better to make the base
class doSomething
method public final synchronized
(final
to make sure subclass can't override it) and call another protected abstract
method. public synchronized final void doSmoething
ensure that any call
to doSomething
method will be synchronized / thread safe
and doSmoethingImpl
abstract method will provide flexibility to give the method own definition in a subclass.
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
}
}
Note: Above solution will not directly satisfy your point 1 but doSmoethingImpl()
will give you scope to achieve the similar functionality indirectly.
来源:https://stackoverflow.com/questions/50545604/how-to-ensure-thread-safety-of-subclass-methods-from-a-superclass