Как сделать метод потокобезопасным, даже если я забуду добавить синхронизацию на уровне метода или блока без изменения файла? - PullRequest
3 голосов
/ 28 января 2020

В то время как у одного из известных собеседований в компании у меня возник вопрос вроде:

У вас есть один класс, и ваш коллега забыл синхронизировать некоторые важные методы. Как сделать потокобезопасным, не переходя в другой класс?

public class Account{

    //some variables

    public boolean withdraw()
    {
        //some business logic
        return true;
    }

    public boolean deposite()
    {
        //some business logic
        return false;
    }
}

Я не уверен, что может быть ответом, Это также может быть глупым ответом. Пожалуйста, помогите мне получить ответ для этого.

Мой ответ: я дал ответ, как будто мы можем сделать обертку над ним, и мы можем синхронизировать. Это был неубедительный ответ, я думал, что это лучшая платформа для получения ответа

Ответы [ 2 ]

4 голосов
/ 28 января 2020

Здесь я вижу два возможных ответа:

  1. Расширение класса Acount и синхронизация доступа к методу:
public class SyncrhonizedAccess extends Account {
   public synchronized boolean withdraw() {
     return super.withdraw();
   }

   public synchronized boolean deposite() {
      return super.deposite();
   }
}
Обтекание класса и синхронизация доступа к обернутому объекту:
public class AccountWrapper {
    private final Account realAcount;

    public AccountWrapper(Account realAccount) {
       this.realAccount = realAccount;
    }

    public synchronized boolean withdraw()
    {
       return realAccount.withdraw();
    }

    public synchronized boolean deposite()
    {
        return realAccount.deposite();
    }
}

Теперь оба метода могут быть выполнены различными способами (вручную, как я показал), автоматически генерируемыми ( это сводится к одному из вышеупомянутых методов, которые просто выполняются "автоматически" такими библиотеками, как CGLIB (библиотека генерации байтового кода)), или даже с использованием AOP (Аспектно-ориентированное программирование).

Еще одно замечание: вместо слова synchronized можно создать блокировку и синхронизировать ее внутри метода внутри.

Конечно, все это имеет смысл, если класс Account имеет общее состояние - поля данных, которые фактически изменены и доступны как withdraw, так и deposite. В противном случае вам не нужно ничего синхронизировать.

0 голосов
/ 28 января 2020

Я бы определенно использовал один аспект и синхронизировал вызовы с методиками. Я бы выбрал эту опцию, учитывая, что, поскольку другие точки моего приложения или сторонних библиотек вызывают методы

Пример кода:

@Aspect
public class AspectAccount {

    private static final Object lock = new Object();

    @Pointcut("execution(* path.to.package.Account.*(..) )")
    public void callAt() {
    }

    @Around("callAt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        synchronized (lock) {
            return pjp.proceed();
        }
    }
}
...