最近在研究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.javaimportjava.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.javapublicclassBankRunnableimplementsRunnable{privateBankbank;privateintfromAccount;privatedoublemaxAmount;privatefinalintDELAY=10;publicBankRunnable(Bankbank,intfrom,doubleamount){this.bank=bank;this.fromAccount=from;this.maxAmount=amount;}@Overridepublicvoidrun(){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.javapublicclassBankRunnableTest{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.00Thread[Thread-1,5,main]784.33from1to84,theremainderis661.14TotalBalance:100000.00Thread[Thread-45,5,main]11.12from45to65,theremainderis9655.22TotalBalance:100000.00Thread[Thread-1,5,main]230.77from1to10,theremainderis430.37TotalBalance:100000.00Thread[Thread-31,5,main]101.21from31to22,theremainderis4781.37TotalBalance:100000.00Thread[Thread-88,5,main]28.85from88to47,theremainderis-1185.99TotalBalance:100000.00Thread[Thread-11,5,main]259.82from11to68,theremainderis-4233.61TotalBalance:100000.00Thread[Thread-71,5,main]704.97from71to10,theremainderis6308.89TotalBalance:100000.00Thread[Thread-15,5,main]116.78from15to80,theremainderis-5700.42TotalBalance:100000.00Thread[Thread-27,5,main]253.64from27to5,theremainderis-3566.59TotalBalance:100000.00Thread[Thread-67,5,main]384.56from67to67,theremainderis-4888.38TotalBalance:100000.00Thread[Thread-33,5,main]925.58from33to46,theremainderis-2872.45TotalBalance:100000.00Thread[Thread-76,5,main]882.94from76to61,theremainderis-10867.94TotalBalance:100000.00Thread[Thread-41,5,main]963.41from41to35,theremainderis-38.63TotalBalance:100000.00Thread[Thread-52,5,main]926.76from52to52,theremainderis-298.91TotalBalance:100000.00Thread[Thread-42,5,main]606.69from42to17,theremainderis734.35TotalBalance:100000.00Thread[Thread-22,5,main]984.00from22to64,theremainderis799.38TotalBalance:100000.00Thread[Thread-59,5,main]165.41from59to6,theremainderis2505.97TotalBalance:100000.00Thread[Thread-38,5,main]886.59from38to9,theremainderis11343.17TotalBalance:100000.00Thread[Thread-1,5,main]872.49from1to20,theremainderis-442.12TotalBalance:100000.00
郎朗坤
繁花如伊
随时随地看视频慕课网APP
相关分类