Как обеспечить потокобезопасность методов подкласса из суперкласса? - PullRequest
0 голосов
/ 26 мая 2018

Я присутствовал на собеседовании, и меня попросили разработать класс для следующего требования.Предположим, у меня есть класс A, и он может иметь любое количество детей, то есть подклассов.Класс A имеет метод doSomething (), который синхронизируется.Требования:

  1. Обязательно, чтобы все подклассы A переопределяли метод doSomething () .
  2. Переопределяли метод doSomething () всех подклассов должен быть поточно-безопасным по своей природе.
  3. Все подклассы 'должны иметь положение для реализации собственной логики для своих реализаций метода doSomething ().
  4. Конструктор класса A - это я (дизайнер), чтобы решить, как его реализовать.

    Дизайнер не может контролировать, сколько подклассов будет создано или как они будут созданы, т.е., разработчик может писать код только для суперкласса .


Я предложил сделать класс абстрактным, а также метод doSomething () абстрактным.Это означало бы, что классы, расширяющие мой класс, обязательно предоставляют свой собственный метод doSomething ().

Однако я не мог ответить, что именно в моем классе A обеспечит безопасность потоков для моих дочерних классов, а также только дляметод doSomething ().

Хотя он намекнул, он сказал, что хитрость должна быть сделана в конструкторе класса.

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 26 мая 2018

Я бы сказал, что лучше сделать метод base class doSomething public final synchronized (final, чтобы убедиться, что подкласс не может его переопределить) и вызвать другой метод protected abstract.public synchronized final void doSmoething гарантирует, что метод от any call до doSomething будет synchronized / thread safe, а абстрактный метод 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, но doSmoethingImpl() даст вам возможность косвенно достичь аналогичной функциональности.

0 голосов
/ 26 мая 2018

После очень долгого исследования я обнаружил, что synchronization нельзя наследовать, если метод переопределен и без явного добавления ключевого слова synchronized в сигнатуру переопределенного метода !!

И поскольку эта проблемав основном предназначен для того, чтобы другие пользователи (например, разработчики) не могли нарушить использование вашего класса (поскольку они расширяют его).

Я нашел способ обойти это, используя класс Reflectionна 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...