How to ensure Thread safety of subclass' methods from a superclass?
Asked Answered
K

2

5

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 :

  1. It is mandatory that all subclasses of A override the doSomething() method.

  2. All subclasses' overriden doSomething() method must be Thread safe in nature.

  3. All subclasses' must have the provision to implement their own logic for their doSomething() method implementations.

  4. 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?

Kiely answered 26/5, 2018 at 17:55 Comment(0)
S
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
}
Standup answered 26/5, 2018 at 18:27 Comment(2)
I do not have any provision to specify a prototype for the children. I cannot do anything to ensure that the subclasses make a call to my superclass constructor in their constructor. I just do not have any control over the children classes. Also, should I have my super class as an abstract class and doSomething() as abstract too?Kiely
@DukeSen super() is called implicitly any way !Standup
S
1

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.

Sirloin answered 26/5, 2018 at 18:37 Comment(7)
Where is It is mandatory that all subclasses of A override the doSomething() method. In your approach they are overriding a different method even if it's the implementation!Standup
And Where is All subclasses' overriden doSomething() method must be Thread safe in nature. because your doSomething() is public and users of subclass can violate it via overriding it too!Standup
@Standup doSomething() can't be override as it is final . But doSomethingImpl() is protected abstract method so any concrete Subclass must need to override doSomethingImpl(). doSomethingImpl() calls come through doSomething, so it will automatically thread-safe (if you are not calling doSomethingImpl directly )Sirloin
Sorry but I have to say that indeed you did not understand the OS question in the first place! The first condition is NOT fulfilled for sure in your approach and it's labeled as mandatory.. otherwise, we would have a bigger space to think about a proper approach!Standup
@Standup OP question was how to force doSmoething will always thread safe when we can change the behavior of doSmoething in the Subclass. And I believe we can achieve the same in my answer.Sirloin
No, OP clearly mentioned: It is mandatory that all subclasses of A OVERRIDE the doSomething() method so it's literally overriding the method, not wrapping it by a different one. If OP did mean something different, so OP question is absolutely mis-wordedStandup
Yes for the first point I admit it is not excat same as OP requiremnt but still doSomethingImpl() method is there to do the job. Thanks!!Sirloin

© 2022 - 2024 — McMap. All rights reserved.