ReentrantLock的trylock方法不允许转换多个线程

时间:2018-01-11 08:22:07

标签: java multithreading reentrantlock

我正在研究MultiThreading个概念。我遇到了ReentrantLock。它有方法locktrylock。当我进一步研究它们时,我知道它们可以用来代替synchronized关键字块或方法。所以我再次尝试了Kathie Sierra书中给出的AccountDanger的经典例子。我观察到lock方法允许转向其他线程。但是trylock布尔方法不允许转向其他线程。以下示例:

使用lock方法

package p1;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class AccountDanger implements Runnable {
    private Account account  = new Account();
    private int amt = 10;
    Lock lock = new ReentrantLock();
    Object obj = new Object();
    public void run(){

        for(int i=0;i<10;i++){
            lock.lock();
            try{
                if(account.getBalance()>=amt){
                    System.out.println(Thread.currentThread().getName()+" is going to withdraw..");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    account.withdraw(amt);
                    System.out.println(Thread.currentThread().getName()+" has withdrawn. Balance left is : "+account.getBalance());
                }
                else{
                    System.out.println("not enough balance for "+Thread.currentThread().getName());
                }
            }finally{
                lock.unlock();
            }
        }
        if(account.getBalance()<0){
            System.out.println("account is over withdrawn!!!");
        }
    }

    public static void main(String[] args) throws InterruptedException{
        AccountDanger ad = new AccountDanger();
        Thread t1 = new Thread(ad,"Mark");
        Thread t2 = new Thread(ad,"Phew");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("final balance left is : "+ad.account.getBalance());
    }
}

上面的代码使用lock方法,允许MarkPhew个线程轮流。

使用trylock方法

package p1;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class AccountDanger implements Runnable {
    private Account account  = new Account();
    private int amt = 10;
    Lock lock = new ReentrantLock();
    Object obj = new Object();
    public void run(){

        for(int i=0;i<10;i++){
            try{
            if(lock.tryLock()){
            if(account.getBalance()>=amt){
                System.out.println(Thread.currentThread().getName()+" is going to withdraw..");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                account.withdraw(amt);
                System.out.println(Thread.currentThread().getName()+" has withdrawn. Balance left is : "+account.getBalance());
            }
            else{
                System.out.println("not enough balance for "+Thread.currentThread().getName());
            }
            }
            }
            finally {
                if(lock.tryLock()){
                    lock.unlock();
                }
            }
            if(account.getBalance()<0){
                System.out.println("account is over withdrawn!!!");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException{
        AccountDanger ad = new AccountDanger();
        Thread t1 = new Thread(ad,"Mark");
        Thread t2 = new Thread(ad,"Phew");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("final balance left is : "+ad.account.getBalance());
    }
}

上面的代码即使在调用Phew方法时也不允许Thread.sleep()线程轮流。

帐户类

package p1;

public class Account{
    private int balance = 100;

    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }


    public void withdraw(int amount){
        this.balance = this.balance - amount;
    }
}
但是,毫无疑问,这两种方法都可以防止平衡变得消极。但是我不明白为什么trylock对这个过程如此认真,以至于即使在Thread.sleep内部调用它也不允许其他线程进入执行之间。即使我在lock.unlock的catch块之后的finally块中使用Thread.sleep语句,也只有mark线程正在执行。

1 个答案:

答案 0 :(得分:1)

你的基本误解是trylock没有获得锁定,它确实存在;正如我在评论中所述,trylock等同于lock,但如果无法获取锁定则不会阻止。

您的案例中发生了什么:

  1. Mark线程启动并获得锁定,然后进入休眠状态0.5秒。
  2. 在这个时候,启动了Phew线程。它试图获得锁定但失败因为Mark有它。
  3. 为Phew启动下一个循环迭代; Phew试图再次获得锁定并失败。这发生在循环运行的10倍。
  4. 循环结束;这退出了线程的run方法并终止了Phew线程。
  5. Mark线程的睡眠结束。
  6. finally块释放锁。
  7. 为Mark开始下一个循环迭代。它试图获得锁定并成功(周围没有其他人可以获得锁定)。同样,这种情况总共发生了10次。