ReentrantLock - параллельная операция по переводу денег - PullRequest
0 голосов
/ 25 декабря 2018

Пока я читал в Интернете несколько примеров кода параллелизма, я нашел этот (операция перевода денег между двумя банковскими счетами):

class Account {
     double balance;
     int id;
     public Account(int id, double balance){
          this.balance = balance;
          this.id = id;
     }
     void withdraw(double amount){
          balance -= amount;
     } 
     void deposit(double amount){
          balance += amount;
     }
}
class Main{
     public static void main(String [] args){
           final Account a = new Account(1,1000);
           final Account b = new Account(2,300);
           Thread a = new Thread(){
                 public void run(){
                     transfer(a,b,200);
                 }
           };
           Thread b = new Thread(){
                 public void run(){
                     transfer(b,a,300);
                 }
           };
           a.start();
           b.start();
     }

И этот фрагмент кода, который касается проблемы параллелизма сиспользование ReentrantLock:

private final Lock lock = new ReentrantLock(); //Addition to the Account class

public static void transfer(Account from, Account to, double amount)
{
       while(true)
        {
          if(from.lock.tryLock()){
            try { 
                if (to.lock.tryLock()){
                   try{
                       from.withdraw(amount);
                       to.deposit(amount);
                       break;
                   } 
                   finally {
                       to.lock.unlock();
                   }
                }
           }
           finally {
                from.lock.unlock();
           }

           Thread.sleep(someRandomTimeToPreventLiveLock);
        }
 }

Мой вопрос: не должны ли методы Acount снять () и deposit () каким-либо образом быть защищены (синхронизированы или заблокированы с полем ReentrantLock), чтобы этот пример работал?Разве не возможно, чтобы другой поток закрался и вызвал метод снятия или депозита?Кроме того, что если есть метод getBalance ()?Должен ли он быть защищен (синхронизирован или заблокирован с помощью ReentrantLock)?

Ответы [ 2 ]

0 голосов
/ 25 декабря 2018

не следует ли каким-либо образом защищать методы изъятия учетной записи () и deposit ()

На самом деле, когда выполняется строка ниже, блок кода защищается объектом Lock(и каждый объект Account имеет свой собственный объект Lock).Таким образом, ни один другой поток не может выполнить тот же код, используя тот же экземпляр Account.

while(true)
    {
      if(from.lock.tryLock()){
        try { 
            if (to.lock.tryLock()){
               try{
          ....
          ....

С другой стороны, когда вы выполняете код, вы создаете несколько объектов Account, что делает каждую передачу независимойдруг другу.Так как каждый Account объект имеет свое собственное состояние (balance, lock)

Кроме того, что если есть метод getBalance ()?Должно ли оно быть защищено тоже

Как указано выше.

0 голосов
/ 25 декабря 2018

Есть два варианта:

(1) Вы делаете свой класс поточно-ориентированным, что означает, что любая операция в любом экземпляре этого класса защищена каким-то внутренним механизмом и абсолютно безопасна в многопоточной среде.Сторона вызывающего абонента не должна заботиться о безопасности потоков.

Это то, что я бы предпочел здесь.Как потребитель вашего API, я бы исключил, что Account#withdraw и Account#deposit были бы самодостаточными, поэтому никаких дополнительных действий не потребовалось бы.

Вот так выглядит хороший API.

(2) Вы возлагаете ответственность за обеспечение корректности и безопасности потоков на сторону вызывающей стороны.Тебе все равно, как это будет достигнуто.

Вот как в настоящее время работают твои фрагменты.Метод transfer является поточно-ориентированным, но он не делает операции с учетными записями такими.

...