ReentrantLock-并发汇款操作

时间:2018-12-25 12:20:15

标签: java multithreading concurrency reentrantlock

当我在互联网上阅读一些并发代码示例时,我发现了这个示例(两个银行帐户之间的转账操作):

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同步或锁定)?

2 个答案:

答案 0 :(得分:0)

有两个选项:

(1)使类成为线程安全的,这意味着对该类任何实例的任何操作均受某种内部机制保护,并且在多线程环境中绝对安全。调用方不必在乎线程安全。

这就是我在这里想要的。作为您的API使用者,我会Account#withdrawAccount#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对象都有其自己的状态(balancelock

  

此外,如果有getBalance()方法怎么办?应该保护吗   也是

如上所述。