如何确保来自超类的子类方法的线程安全?

Duk*_*Sen 5 java inheritance synchronization

我参加了一次面试,并被要求为以下要求设计一个课程。假设我有一个 A 类,它可以有任意数量的子类,即子类。类 A 有一个名为 doSomething() 的方法,它是同步的。要求是:

  1. A 的所有子类都必须覆盖 doSomething()方法。

  2. 所有子类的重写 doSomething() 方法本质上必须是线程安全的。

  3. 所有子类都必须为它们的 doSomething() 方法实现提供自己的逻辑

  4. A 类的构造函数由我(设计者)决定如何实现。

    设计者无法控制将创建多少子类或如何创建它们,即设计者只能为超类编写代码


我建议将类抽象化,并将 doSomething() 方法抽象化。这意味着扩展我的类的类必须提供自己的 doSomething() 方法。

但是,我无法回答在我的类 A 中究竟什么可以确保我的子类的线程安全,而这也仅适用于 doSomething() 方法。

不过他给出了一个提示,他说诀窍是在 A 类的构造函数中完成。

有任何想法吗?

Yah*_*hya 1

经过很长时间的研究,我发现synchronization如果方法被重写并且没有synchronized在被重写方法的签名中显式添加关键字,则无法继承!

因为这个问题主要是为了防止其他用户(即开发人员)违反您的类的使用(因为他们正在扩展它)。

我想出了一种方法来解决这个问题,即利用ReflectionJava 中的类。

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() {} 
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)