当我在互联网上阅读一些并发代码示例时,我发现了这个示例(两个银行账户之间的转账操作):
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的or ()方法(与ReentrantLock字段同步或锁定)吗?难道其他线程不可能潜入并调用取款或存款方法吗?此外,如果有getBalance()方法,怎么办?它是否也应该受到保护(与ReentrantLock同步或锁定)?
发布于 2018-12-25 12:36:37
有两种选择:
(1)使类线程安全,意味着对该类任何实例的任何操作都由某种内部机制保护,并且在多线程环境中是绝对安全的。调用方不应该关心线程安全。
这才是我想要的。作为API的使用者,除了Account#withdraw和Account#deposit之外,我想要自给自足,所以不需要额外的操作。
在我看来,这就是一个好的API。
(2)将提供正确性和线程安全的责任放在调用方。你不在乎它是如何实现的。
这就是你的片段目前的工作方式。方法transfer是线程安全的,但它不会使帐户操作如此。
发布于 2018-12-25 12:41:25
帐户的取款()和存款()方法不应该受到某种保护吗?
实际上,当下面的代码行执行时,代码块被Lock对象保护(每个帐户对象都有自己的Lock对象)。因此,没有其他线程可以使用相同的Account实例执行相同的代码。
while(true)
{
if(from.lock.tryLock()){
try {
if (to.lock.tryLock()){
try{
....
....另一方面,当您执行代码时,您正在创建多个Account对象,这使得每个传输相互独立。每个Account对象都有自己的状态(balance,lock )
此外,如果有getBalance()方法,怎么办?它也应该受到保护吗?
如上段所述。
https://stackoverflow.com/questions/53922340
复制相似问题