【问题标题】:Synchronize 2 methods同步2种方法
【发布时间】:2015-09-22 11:19:53
【问题描述】:
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);
    }
}

线程类型 1:用户可以点击“保存”按钮,在这种情况下方法 save() 将直接调用。我从 SecurityContext 获得帐户。

线程类型2:用户启动后台进程。我保存他/她的帐户,然后开始新线程:

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

问题:变量 this.temporaryAccount 可以更改 - 在调用 saveByAccount() 和 save() 之间。 您知道同步这些方法的正确方法吗?

【问题讨论】:

  • 为什么要在类级别存储一个临时变量,我们不能在不同的方法调用之间共享帐户,例如 save(account);从 saveByAccount 中
  • @Akash Yadav 方法 save() 在我们项目的很多地方使用。更改签名是个问题。
  • 添加一个包含实际逻辑的新方法save( Account a ),并从save()等调用save(temporaryAccount)
  • 除了将帐户作为参数传递之外,您还可以尝试使访问temporaryAccount的每个方法或代码块同步(代码块使用synchronized(this))。
  • 既然temporaryAccount 是一个私有成员,只能通过save() 设置,为什么不让save 方法同步,你应该好好去

标签: java multithreading synchronized java.util.concurrent


【解决方案1】:

解决此问题的最佳方法是将帐户作为参数发送到每个方法。封装总是一个很好的特性,你应该尽可能地争取它。这样,当你需要并行化时,你就不会遇到这种麻烦了。

鉴于您无法更改方法签名的评论,我建议您在开始使用共享变量之前使用信号量。

您可以使用以下代码在类级别创建信号量:

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

在尝试更改或使用共享变量之前,每个方法都必须调用available.acquire();。如果信号量正在使用中,这将阻塞(因为您有一个许可,如构造函数调用中所定义),但如果它是空闲的,则它将许可数量减少一并继续。

在完成依赖共享变量的处理后,每个方法都应该调用available.release();。然后,等待服务的其他方法之一将获取信号量并继续。

不过,我强烈建议您花时间重构您的代码。全局变量和类变量是“代码气味”,将来可能会引发错误。花费在此重构上的时间将在未来得到回报。这种类型的讨论可以在“代码完整”和“干净代码”等优秀书籍中找到。它们是必读之物,为我们程序员提供了很多关于代码质量的见解。

我希望这会有所帮助。

【讨论】:

  • 谢谢,我正在努力理解 Semaphore 的语义。
猜你喜欢
  • 2018-02-28
  • 1970-01-01
  • 2012-07-30
  • 1970-01-01
  • 2019-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-04
相关资源
最近更新 更多