当我在互联网上阅读一些并发代码示例时,我发现了这个示例(两个银行帐户之间的转账操作):
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的withdraw()和deposit()方法(与ReentrantLock字段同步或锁定)吗?其他线程是否有可能进入并调用撤回或存款方法?另外,如果有getBalance()方法怎么办?它是否也应该受到保护(与ReentrantLock同步或锁定)?
答案 0 :(得分:0)
有两个选项:
(1)使类成为线程安全的,这意味着对该类任何实例的任何操作均受某种内部机制保护,并且在多线程环境中绝对安全。调用方不必在乎线程安全。
这就是我在这里想要的。作为您的API使用者,我会Account#withdraw
和Account#deposit
之外的其他人都是自给自足的,因此不需要采取任何其他措施。
这就是一个好的API对我的外观。
(2)您负责在调用方提供正确性和线程安全性。您不在乎如何实现它。
这就是您的代码段当前的工作方式。方法transfer
是线程安全的,但不会使帐户操作如此。
答案 1 :(得分:0)
该帐户的withdraw()和deposit()方法是否应以某种方式 受保护的
实际上,当执行下面的代码行时,代码块将由Lock
对象保护(每个Account对象都有自己的Lock
对象)。因此,没有其他线程可以使用相同的Account
实例执行相同的代码。
while(true)
{
if(from.lock.tryLock()){
try {
if (to.lock.tryLock()){
try{
....
....
另一方面,在执行代码时,您正在创建多个Account
对象,这使每次传输彼此独立。因此,每个Account
对象都有其自己的状态(balance
,lock
)
此外,如果有getBalance()方法怎么办?应该保护吗 也是
如上所述。