java多线中的条件对象await()问题

最近在研究java多线程,在研究到条件对象的时候,问题出现了。本来该阻塞的线程,没有阻塞。
情景如下:
有一个银行类Bank,Bank有一个方法用来从一个账户转账到另外一个账户。实现逻辑如下:
try{
bankLock.lock();//获取锁
if(accounts[from]//return;
sufficientFunds.await();//保证账户金额不会为负
}
System.out.print(Thread.currentThread());
accounts[from]-=amount;
System.out.printf("%10.2ffrom%dto%d,theremainderis%10.2f",amount,from,to,accounts[from]);
accounts[to]+=amount;
System.out.printf("TotalBalance:%10.2f%n",getTotalBalance());
sufficientFunds.signalAll();//唤醒条件对象等待队列中的所有等待的线程
}finally{
bankLock.unlock();//释放锁
}
在每次转账前,获取锁,保证操作的原子性,然后判断账户金额是否足够转账金额,如果不够,通过条件对象等待,并释放同步锁,以保证其他线程可以获取该锁,并给该账户充值,如果够,则进行转账,转账结束后唤醒条件对象上等待的所有线程,所有操作都结束后释放锁。
同时有一个线程对象一直调用Bank对象的转账方法,进行转账。实现逻辑如下:
try{
while(true){
//获取一个随机账户
inttoAccount=(int)(bank.size()*Math.random());
//获取随机转账金额
doubleamount=maxAmount*Math.random();
//调用转账方法
bank.transfer(fromAccount,toAccount,amount);
Thread.sleep((int)(DELAY*Math.random()));
}
}catch(InterruptedExceptione){
}
最后是一个启动线程测试类:
Bankb=newBank(NACCOUNTS,INITIAL_BALANCE);
inti;
for(i=0;iBankRunnabler=newBankRunnable(b,i,INITIAL_BALANCE);
Threadt=newThread(r);
t.start();
}
这个类就是循环创建与银行账户相同个数的线程,一个线程负责一个账户金额的转出,转入到一个随机的账户中。
执行上面的代码,理论上每个账户的余额都不可能为负,因为在每次转账的时候就会进行账户余额与转账金额的比较,如果不够,就是通过条件对象调用await()使当前线程阻塞,直到其他线程调用了signalAll()唤醒该条件对象上等待的线程,但是signalAll()也并不是让这些等待的线程立即激活,而是仅仅解除了等待线程的阻塞,与其他线程重新竞争同步锁。所以当线程重新获得同步锁后,他依然会继续进行余额校验。。。这样的话账户余额是不可能为负值的。
但是问题是当循环进行转账是有些账户却莫名其妙的出现了负值,有点不解,希望大神指教。
下面是测试代码的完整版本:
Bank.java
importjava.util.concurrent.locks.Condition;
importjava.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
publicclassBank{
privatefinaldouble[]accounts;
//锁
privateLockbankLock;
privateConditionsufficientFunds;
publicBank(intn,doubleinitialBalance){
accounts=newdouble[n];
for(inti=0;iaccounts[i]=initialBalance;
}
bankLock=newReentrantLock();
sufficientFunds=bankLock.newCondition();
}
publicvoidtransfer(intfrom,intto,doubleamount)throwsInterruptedException{
try{
bankLock.lock();//获取锁
if(accounts[from]//return;
sufficientFunds.await();//保证账户金额不会为负
}
System.out.print(Thread.currentThread());
accounts[from]-=amount;
System.out.printf("%10.2ffrom%dto%d,theremainderis%10.2f",amount,from,to,accounts[from]);
accounts[to]+=amount;
System.out.printf("TotalBalance:%10.2f%n",getTotalBalance());
sufficientFunds.signalAll();//唤醒条件对象等待队列中的所有等待的线程
}finally{
bankLock.unlock();//释放锁
}
}
publicdoublegetTotalBalance()throwsInterruptedException{
bankLock.lock();
try{
doublesum=0;
for(doubled:accounts){
sum+=d;
}
returnsum;
}finally{
bankLock.unlock();
}
}
publicintsize(){
returnaccounts.length;
}
}
BankRunnable.java
publicclassBankRunnableimplementsRunnable{
privateBankbank;
privateintfromAccount;
privatedoublemaxAmount;
privatefinalintDELAY=10;
publicBankRunnable(Bankbank,intfrom,doubleamount){
this.bank=bank;
this.fromAccount=from;
this.maxAmount=amount;
}
@Override
publicvoidrun(){
try{
while(true){
inttoAccount=(int)(bank.size()*Math.random());
doubleamount=maxAmount*Math.random();
bank.transfer(fromAccount,toAccount,amount);
Thread.sleep((int)(DELAY*Math.random()));
}
}catch(InterruptedExceptione){
}
}
}
BankRunnableTest.java
publicclassBankRunnableTest{
privatestaticfinalintNACCOUNTS=100;
privatestaticfinaldoubleINITIAL_BALANCE=1000;
publicstaticvoidmain(String[]args){
Bankb=newBank(NACCOUNTS,INITIAL_BALANCE);
inti;
for(i=0;iBankRunnabler=newBankRunnable(b,i,INITIAL_BALANCE);
Threadt=newThread(r);
t.start();
}
}
}
执行结果部分:
Thread[Thread-5,5,main]270.14from5to30,theremainderis9373.35TotalBalance:100000.00
Thread[Thread-1,5,main]784.33from1to84,theremainderis661.14TotalBalance:100000.00
Thread[Thread-45,5,main]11.12from45to65,theremainderis9655.22TotalBalance:100000.00
Thread[Thread-1,5,main]230.77from1to10,theremainderis430.37TotalBalance:100000.00
Thread[Thread-31,5,main]101.21from31to22,theremainderis4781.37TotalBalance:100000.00
Thread[Thread-88,5,main]28.85from88to47,theremainderis-1185.99TotalBalance:100000.00
Thread[Thread-11,5,main]259.82from11to68,theremainderis-4233.61TotalBalance:100000.00
Thread[Thread-71,5,main]704.97from71to10,theremainderis6308.89TotalBalance:100000.00
Thread[Thread-15,5,main]116.78from15to80,theremainderis-5700.42TotalBalance:100000.00
Thread[Thread-27,5,main]253.64from27to5,theremainderis-3566.59TotalBalance:100000.00
Thread[Thread-67,5,main]384.56from67to67,theremainderis-4888.38TotalBalance:100000.00
Thread[Thread-33,5,main]925.58from33to46,theremainderis-2872.45TotalBalance:100000.00
Thread[Thread-76,5,main]882.94from76to61,theremainderis-10867.94TotalBalance:100000.00
Thread[Thread-41,5,main]963.41from41to35,theremainderis-38.63TotalBalance:100000.00
Thread[Thread-52,5,main]926.76from52to52,theremainderis-298.91TotalBalance:100000.00
Thread[Thread-42,5,main]606.69from42to17,theremainderis734.35TotalBalance:100000.00
Thread[Thread-22,5,main]984.00from22to64,theremainderis799.38TotalBalance:100000.00
Thread[Thread-59,5,main]165.41from59to6,theremainderis2505.97TotalBalance:100000.00
Thread[Thread-38,5,main]886.59from38to9,theremainderis11343.17TotalBalance:100000.00
Thread[Thread-1,5,main]872.49from1to20,theremainderis-442.12TotalBalance:100000.00
郎朗坤
浏览 956回答 2
2回答

繁花如伊

if(accounts[from]
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript