2015-09-22 3 views
0
public class ActionForm { 
     private Account temporaryAccount = null; 
     private Document document; 

     /** 
     * Save document from another thread that do not have a SecurityContext 
     */ 
     public void saveByAccount(Account account) { 
      this.temporaryAccount = account; 
      save(); 
      this.temporaryAccount = null; 
     } 

     /** 
     * Save document to DB. 
     * I can not change the signature of this method. 
     */ 
     public synchronized void save() { 

      //get an account from shared variable or from SecurityContext 
      Account account = null; 
      Account temporaryAccount = this.temporaryAccount; 
      if (temporaryAccount == null) { 
       account = SecurityContextWrapper.getAccount(); 
      } else { 
       account = temporaryAccount; 
      } 

     //save in DB 
     saveDocumentInDB(account, document); 
    } 
} 

type1 Thread: Пользователь может нажать кнопку "сохранить", в этом случае метод Save() будет вызывать непосредственно. Я получаю аккаунт из SecurityContext.Синхронизировать 2 Методы

Тип темы2: Пользователь запускает фоновый процесс. Я сохранить его/ее счет, а затем начать новую тему:

final Account account = SecurityContextWrapper.getAccount(); 
new Thread(new Runnable() { 
    public void run() { 
     ...//do smth 
     saveByAccount(account); 
    } 
}).start(); 

Проблема: Переменная this.temporaryAccount может быть изменен - ​​между вызовом saveByAccount() и сохранить(). Знаете ли вы, как правильно синхронизировать эти методы?

+1

Почему вы храните временную переменную на уровне класса, не можем ли мы разделить учетную запись между различными вызовами методов, например save (account); изнутри saveByAccount –

+0

@Akash Yadav Метод save() используется во многих местах нашего проекта. Проблема заключается в изменении подписи. –

+0

Добавьте новый метод 'save (Account a)', который содержит фактическую логику и вызовет 'save (temporAccount)' из 'save()' и т. Д. – Thomas

ответ

0

Лучший способ решить эту проблему - отправить учетную запись каждому методу в качестве параметра. Инкапсуляция всегда хорошая функция, и вы должны стремиться к ней, когда это возможно. Таким образом, когда вам понадобится паралелизировать, вы не столкнетесь с такими неприятностями.

Учитывая, что вы не можете изменить подпись метода, я бы предложил вам использовать семафор, прежде чем использовать общую переменную.

Вы можете создать на уровне класса семафор, используя следующий код:

private final Semaphore available = new Semaphore(1, true); 

Каждый метод, прежде чем пытаться изменить или использовать совместно с переменной должен был бы назвать available.acquire();. Это заблокировало бы, если семафор был в использовании (поскольку у вас есть одно разрешение, как определено в вызове конструктора), но если оно было бесплатным, оно затем уменьшало бы количество разрешений на единицу и продолжалось.

После завершения обработки, зависящей от общей переменной, каждый метод должен вызывать available.release();. Затем один из других методов, ожидающих обслуживания, получит семафор и продолжит работу.

Тем не менее, я настоятельно рекомендую вам потратить время и реорганизовать свой код. Глобальные переменные и переменные класса являются «запахами кода» и могут вызывать ошибки в будущем. Время, проведенное с этим рефактором, окупится интересом к будущему. Этот тип обсуждения доступен в таких замечательных книгах, как «Code Complete» и «Clean Code». Они должны читать и предлагать нам, программистам, много понимания качества кода.

Надеюсь, это поможет.

+0

спасибо, я пытаюсь понять семантику Семафора. –