条件对象
通常线程进入临界区,需要满足一定的条件才能运行。就像上一篇中的银行例子,账户中的金额大于要转账的金额才可以进行转账操作,否则就要阻塞,知道账户中金额达到要求才可以执行。因此,需要使用条件对象管理那些已经获得了锁,却不能做有用工作的线程。
一个锁对象可以有一个或多个相关的条件对象。可以使用newCondition方法获得一个条件对象。例如设置一个条件对象表达余额充足:
class bank
{
private Condition sufficientFunds;
private Lock banklock;
public bank()
{
banklock=new ReectrantLock();
sufficientFunds=banklock.newCondition();
}
}
如果transfer方法发现余额不足,可以调用sufficientFunds.await();当前线程即被阻塞,并放弃了锁。如果不是用条件对象的话,当前线程由于不满足条件不能继续执行,而且还占用着锁,其他线程也不能执行。这就会造成死锁。
等待获得锁的线程和调用await方法的线程存在本质上的不同。一旦一个线程调用await方法,它进入该方法的等待集。当锁可用时,该线程不能马上解除阻塞。相反,它处于阻塞状态,直到另一个线程调用同意条件上的signalAll方法时为止。bank类应修改为:
class Bank
{
private final double[] accounts;
private Lock banklock;
private Condition sufficientFunds;
public Bank(int n,double initialBalance)
{
banklock=new ReentrantLock();
sufficientFunds=banklock.newCondition();
accounts=new double[n];
Arrays.fill(accounts,initialBalance);
}
public void transfer(int from,int to,double amount)
{
banklock.lock();
try
{
if(accounts[from]<amount) sufficientFunds.await();
System.out.print(Thread.currentThread());
accounts[from]-=amount;
System.out.printf("%10.2f from %d to %d ",amount,from,to);
accounts[to]+=amount;
System.out.printf("Total Balance :%10.2f\n",getTotalBalance());
sufficientFunds.signalAll();
}
catch(InterruptedException e){}
finally{banklock.unlock();}
}
public double getTotalBalance()
{
banklock.lock();
try
{
double sum=0;
for(double money:accounts)
sum+=money;
return sum;
}
finally{banklock.unlock();}
}
public int size()
{
return accounts.length;
}
}