日期:2014-05-20  浏览次数:20718 次

多线程——signalall()的问题
我最近在学习Core   Java   2   第二卷,看到1.5.4节(条件对象)的示例代码时,遇到了一个问题:
在   JDK1.5   中,   java.util.concurrent.locks.Lock用于保护代码片断,保证该代码片断在莫一时刻只被一个线程使用;java.util.concurrent.locks.Condition用于管理已进入被保护的代码段但还不能运行的线程。
在例1-4中,有一个类Bank,它有一个transfer方法,该方法受到了Lock的保护以及Condition的管理。transfer方法的作用是从一个账户取出一定数额的钱,放入另一个账户中。

class   Bank
{
public   Bank(int   n,   double   initialBalance)
{
accounts   =   new   double[n];
for   (int   i   =   0;   i   <   n;   i++)
{
accounts[i]   =   initialBalance;
}
}

public   void   transfer(int   from,   int   to,   double   amount)   throws   InterruptedException
{
bankLock.lock();
try
{
while   (accounts[from]   <   amount)
{
sufficientFund.await();
}
System.out.println(Thread.currentThread());
accounts[from]   -=   amount;
System.out.println( "from   "   +   from   +   "   to   "   +   to   +   "   amount= "   +   amount);
accounts[to]   +=   amount;
System.out.println( "Total   Balance   :   "   +   this.getTotalBalance());
                                                        sufficientFund.signalAll();
        }
        finally
        {
       
        bankLock.unlock();        
        }  
}

private   double   getTotalBalance()
{
bankLock.lock();
try
{
double   sum   =   0;
for   (int   i   =   0;   i   <   accounts.length;   i++)
{
sum   +=   accounts[i];
}
return   sum;
}
finally
{
bankLock.unlock();
}
}

public   int   size()
{
return   accounts.length;
}

private   final   double[]   accounts;
private   Lock   bankLock   =   new   ReentrantLock();
private   Condition   sufficientFund   =   bankLock.newCondition();
}

我一直很好奇为什么在transfer方法中,sufficientFund.signalAll();是不是只能放在如上所示的位置。后来发现,sufficientFund.signalAll();在放到bankLock.unlock();之后时,会出现异常。当我将transfer方法修改为如下代码时:

public   void   transfer(int   from,   int   to,   double   amount)   throws   InterruptedException
{
bankLock.lock();
try
{
while   (accounts[from]   <   amount)
{
sufficientFund.await();
}
System.out.println(Thread.currentThread());
accounts[from]   -=   amount;
System.out.println( "from   "   +   from   +   "   to   "   +   to   +   "   amount= "   +   amount);
accounts[to]   +=   amount;
System.out.println( "Total   Balance   :   "   +   this.getTotalBalance());
        }
        finally