“Core Java”一书中有一个示例,它将资金从一个帐户转移到另一个帐户。我不知道条件的用处是什么?在书中,它告诉我们:
if we just lock and wait without condition, it gets a deadlock:
private final double[] accounts;
private Lock bankLock;
private Condition sufficientFunds;
public void transfer(int from, int to, int amount) {
bankLock.lock();
try {
while (accounts[from] < amount) {
// wait...
}
// transfer funds . . .
} finally {
bankLock.unlock();
}
}
Now, what do we do when there is not enough money in the account? We wait until some other thread has added funds. But this thread has just gained exclusive access to the
bankLock
, so no other thread has a chance to make a deposit.When call
sufficientFunds.await();
the current thread is now deactivated and gives up the lock. This lets in another thread that can, we hope, increase the account balance.
Lock
锁定代码,而条件放弃了锁定,但是我不知道什么是条件,为什么在钱不够的情况下为什么不简单地解锁块呢?线程状态“阻塞”和“等待”之间有什么区别?
阻塞:线程无法运行;
等待中:线程也无法运行。
有什么不同吗?
另一个问题:
while (accounts[from] < amount) {
...
sufficientFunds.await();
为什么不写
if
?if (accounts[from] < amount) {
...
最佳答案
Bank
类有一个特殊要求:如果要求将一定数量的钱从一个帐户转移到另一个帐户,并且源帐户上没有足够的资金,则它必须等到存入足够的钱才能进行转移。您可以运行一个循环,以检查每次迭代是否有足够的资金,并仅在满足以下条件时获取锁:
while (true) {
if (accounts[from] >= amount) {
bankLock.lock();
try {
if (account[from] >= amount) {
// do the transfer here...
break;
}
} finally {
bankLock.unlock();
}
}
}
但是这种方法:
在几小时或几天内存足够的钱?)
因此,您需要某种机制来告诉您,您只是在等待帐户中的某些更改。如果没有人存入钱,一次又一次地检查一个账户中的钱是浪费的。不仅如此,您还需要在有人存入资金后立即获取锁,这样您就可以专门检查新帐户的状态,并决定是否可以进行转帐。
您还必须记住,存款不是帐户上唯一允许的操作。例如,也有提款。如果有人提款,则无需检查您的帐户是否有转账的可能性,因为我们可以确定现在这笔钱甚至更少。因此,我们希望在存款时醒来,但又不想在提款时醒来。我们需要以某种方式将它们分开。这是发挥条件的地方。
条件是实现
Condition
接口(interface)的对象。这只是一个抽象,允许您将锁定/等待逻辑划分为多个部分。在我们的例子中,我们可能有两个条件:一个用于增加帐户余额,另一个用于减少余额(例如,如果有人在等待将银行帐户清零以将其关闭):sufficientFunds = bankLock.newCondition();
decreasedFunds = bankLock.newCondition();
现在,您无需在循环中进行大量的检查,您可以通过以下方式组织程序:仅当有人向一个帐户存入资金时,您才可以唤醒并检查该帐户:
private final double[] accounts;
private Lock bankLock;
private Condition sufficientFunds;
public void transfer(int from, int to, int amount) {
bankLock.lock();
try {
while (accounts[from] < amount) {
sufficientFunds.await();
}
// transfer funds ...
sufficientFunds.signalAll();
} finally {
bankLock.unlock();
}
}
public void deposit(int to, int amount) {
bankLock.lock();
try {
// deposit funds...
sufficientFunds.signalAll();
} finally {
bankLock.unlock();
}
}
因此,让我们看看这里发生了什么,并回答您的问题:
transfer()
试图获取bankLock
。如果有人已经持有此锁,则在释放该锁之前,您的线程将被另一个线程阻塞。 sufficienFunds.await()
。它使您的线程等待发生的事情。您决定这样做,而不仅仅是因为另一个线程而被阻塞,那就是阻塞和等待之间的区别。但是您是对的,在两种情况下您的线程都没有运行,因此区别更合乎逻辑,而不是技术上的区别。 await()
上创建的条件下调用bankLock
会释放此锁,并使该锁可用于其他线程来获取和执行操作。如果不释放锁,线程将阻止存储区中的所有操作并导致死锁。 sufficientFunds
条件,我们的传输线程醒来,循环可以再次进行检查。在这里,我们有两件事要看。首先,当我们的线程唤醒时,它会自动重新获取该锁,因此我们可以确保我们可以排他地,安全地进行检查和修改。其次,可能发生的是新的金额仍然不足以进行转帐(在某种情况下进行信号通知仅表示发生了可能会改变您正在等待的状态,但不能保证该状态的事情)。在这种情况下,我们必须等待下一次存款。这就是为什么我们必须使用while
循环,而不是简单的if
的原因。 sufficienFunds.signalAll()
,因为我们增加了to
帐户中的金额。如果某个其他线程正在等待该帐户的注资,则它将获得该锁并可以开始工作。 因此,使用锁和条件可以使您以安全有效的方式组织多线程程序。
关于java - 为什么要使用条件,“阻塞”和“等待”之间有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39050057/