Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何确保子类'的线程安全;来自超类的方法?_Java_Inheritance_Synchronization - Fatal编程技术网

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

Java 如何确保子类'的线程安全;来自超类的方法?,java,inheritance,synchronization,Java,Inheritance,Synchronization,我参加了一次面试,被要求根据以下要求设计一门课程。 假设我有一个类a,它可以有任意数量的子类,即子类。 类A有一个名为doSomething()的方法,该方法是同步的。这些要求是: 的所有子类都必须重写doSomething()方法 所有子类重写的doSomething()方法本质上必须是线程安全的 所有子类的doSomething()方法实现都必须有规定来实现自己的逻辑 A类的构造函数由我(设计者)决定如何实现 设计器无法控制将创建多少子类或如何创建子类,即,设计器只能为超类编写代码

我参加了一次面试,被要求根据以下要求设计一门课程。 假设我有一个类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
    class
    doSomething
    方法
    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()也作为抽象类吗?@DukeSen
    super()
    以任何方式隐式调用!其中,强制所有子类重写doSomething()方法。在您的方法中,它们覆盖了不同的方法,即使它是实现!所有子类重写的doSomething()方法在本质上必须是线程安全的。因为您的
    doSomething()
    是公共的,子类的用户也可以通过重写它来违反它@Yahya
    doSomething()
    无法覆盖,因为它是
    最终版
    。但是
    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
        }
    }