同步2个方法
Synchronize 2 methods
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",此时save()方法会直接调用。我从 SecurityContext 获取帐户。
线程类型 2: 用户启动后台进程。我保存 his/her 帐户然后开始新线程:
final Account account = SecurityContextWrapper.getAccount();
new Thread(new Runnable() {
public void run() {
...//do smth
saveByAccount(account);
}
}).start();
问题:变量this.temporaryAccount可以改变——在调用saveByAccount()和save()之间。
你知道同步这些方法的正确方法吗?
解决这个问题的最好方法是将帐户作为参数发送到每个方法。封装始终是一个很好的特性,您应该尽可能地争取它。这样,当你需要并行化时,你就不会遇到这种麻烦了。
考虑到您不能更改方法签名的评论,我建议您在开始使用共享变量之前使用信号量。
您可以使用以下代码在 class 级别创建信号量:
private final Semaphore available = new Semaphore(1, true);
每个方法在尝试更改或使用共享变量之前都必须调用 available.acquire();
。如果信号量正在使用中(因为您只有一个许可,如构造函数调用中定义的那样),这将阻塞,但如果它是空闲的,它将减少一个许可数量并继续。
依赖于共享变量的处理完成后,每个方法都应该调用available.release();
。然后,等待服务的其他方法之一将获取信号量并继续。
尽管如此,我还是强烈建议您花时间重构您的代码。全局和 class 变量是 "code smells" 并且将来可能会导致错误。花在这次重构上的时间会在未来得到回报。这种类型的讨论可以在 "Code Complete" 和 "Clean Code" 等优秀书籍中找到。它们是必读的,并为我们程序员提供了很多关于代码质量的见解。
希望对您有所帮助。
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",此时save()方法会直接调用。我从 SecurityContext 获取帐户。
线程类型 2: 用户启动后台进程。我保存 his/her 帐户然后开始新线程:
final Account account = SecurityContextWrapper.getAccount();
new Thread(new Runnable() {
public void run() {
...//do smth
saveByAccount(account);
}
}).start();
问题:变量this.temporaryAccount可以改变——在调用saveByAccount()和save()之间。 你知道同步这些方法的正确方法吗?
解决这个问题的最好方法是将帐户作为参数发送到每个方法。封装始终是一个很好的特性,您应该尽可能地争取它。这样,当你需要并行化时,你就不会遇到这种麻烦了。
考虑到您不能更改方法签名的评论,我建议您在开始使用共享变量之前使用信号量。
您可以使用以下代码在 class 级别创建信号量:
private final Semaphore available = new Semaphore(1, true);
每个方法在尝试更改或使用共享变量之前都必须调用 available.acquire();
。如果信号量正在使用中(因为您只有一个许可,如构造函数调用中定义的那样),这将阻塞,但如果它是空闲的,它将减少一个许可数量并继续。
依赖于共享变量的处理完成后,每个方法都应该调用available.release();
。然后,等待服务的其他方法之一将获取信号量并继续。
尽管如此,我还是强烈建议您花时间重构您的代码。全局和 class 变量是 "code smells" 并且将来可能会导致错误。花在这次重构上的时间会在未来得到回报。这种类型的讨论可以在 "Code Complete" 和 "Clean Code" 等优秀书籍中找到。它们是必读的,并为我们程序员提供了很多关于代码质量的见解。
希望对您有所帮助。