ReentrantLock的trylock方法不允许多线程轮流

ReentrantLock's trylock method not allowing turn taking of multiple threads

我正在研究 MultiThreading 概念。我遇到了 ReentrantLock。它有方法 locktrylock。当我进一步研究它们时,我了解到它们可以用来代替 synchronized 关键字块或方法。所以我用 Kathie Sierra 书中给出的 classic 示例 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() 方法。

帐号class

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 也是如此。即使我在 Thread.sleep 的 catch 块之后的 finally 块中使用 lock.unlock 语句,也只有 mark 线程正在执行。

您的基本误解是 trylock 没有获得锁,但确实如此;正如我在评论中所述,trylock 等同于 lock 除了如果无法获得锁它不会阻塞。

你的情况是这样的:

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