原代码用的if-else对flag进行判断,这里存在问题,直接导致不论存款(或取款)成功或失败(即wait),run()方法的循环计数器都会自增1,导致存款(或取款)次数比预计的少,进而导致存款(取款线程已执行完,而存款线程仍在执行)或取款(存款线程已执行完,而取款线程仍在执行)线程阻塞
应当采用while进行循环判断,线程被唤醒之后,应再次进行判断,而不是直接将循环计数器自增,可以保证在每个循环中都成功进行了一次存款
调用Condition对象的的await()、signal()、signalAll()方法实现线程间通信上面Object的wait()、notify()、notifyAll()方法只能适用于this、显式的Object对象
对于用Lock进行加锁的同步方法,上面的三个方法则不适用,这时候得靠Condition对象的另外三个方法
通过Lock锁的newCondition()方法返回一个Condition对象,然后调用该对象的下面三个方法进行通信
await()
类似于wait()方法
await(long timeout,int nanos)
awaitnanos(long nanosTimeout)
awaitUninterruptibly()
awaitUntil(Date deadline)
signal()
类似于notify()
signalAll()
类似于notifyAll()
Lock锁的newCondition()方法返回的是ConditionObject对象,这是AbstractQueuedSynchronizer抽象类的一个内部类,该内部类实现了Condition接口
下面用Lock及这三个新方法改写上面的Account类
class Account { private String accountNO; private double balance; private boolean flag=false; private final ReentrantLock lock=new ReentrantLock(); //创建一把Lock锁 private final Condition cond=lock.newCondition(); //返回Condition对象 public Account(){} public Account(String no,double balance){ accountNO=no; this.balance=balance; } public double getBalance(){ return balance; } public void withdraw(double amount){ lock.lock(); //获取锁并加锁 try { while (!flag){ cond.await(); //调用Condition对象的await()方法 } System.out.println(Thread.currentThread().getName()+"取款:"+amount); balance-=amount; System.out.println("取款后,余额为: "+balance); flag=false; System.out.println("---------------上面取款完毕-------------------"); cond.signalAll(); }catch(InterruptedException ex){ ex.printStackTrace(); }finally{ lock.unlock(); //释放锁 } } public void deposit(double amount){ lock.lock(); try{ while (flag){ cond.await(); } System.out.println(Thread.currentThread().getName()+"存款"+amount); balance+=amount; System.out.println("存款后,账户余额为: "+balance); flag=true; System.out.println("---------------上面存款完毕-------------------"); cond.signalAll(); }catch(InterruptedException ex){ ex.printStackTrace(); }finally{ lock.unlock(); } } } 如果调用了Lock对象的wait()、notify()、notifyAll()方法会怎样?Lock对象也是Object的子类的实例,也拥有这三个方法,按理说调用Lock对象这个同步监视器的该三个方法,也应该能达到通信的目的
改写后,程序输出如下:
存款者A存款325.0Exception in thread "存款者A" Exception in thread "取款者甲" //
存款后,账户余额为: 325.0
---------------上面存款完毕-------------------
取款者甲取款:325.0
取款后,余额为: 0.0
---------------上面取款完毕-------------------
存款者B存款325.0
存款后,账户余额为: 325.0
---------------上面存款完毕-------------------
Exception in thread "存款者B" 取款者乙取款:325.0
取款后,余额为: 0.0
java.lang.IllegalMonitorStateException
---------------上面取款完毕-------------------
at java.lang.Object.notifyAll(Native Method)
at testpack.Account.deposit(Test1.java:86)
at testpack.Deposit.run(Test1.java:39)
Exception in thread "取款者乙" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at testpack.Account.withdraw(Test1.java:68)
at testpack.Withdraw.run(Test1.java:25)
java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at testpack.Account.withdraw(Test1.java:68)
at testpack.Withdraw.run(Test1.java:25)
java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at testpack.Account.deposit(Test1.java:86)
at testpack.Deposit.run(Test1.java:39)
上面出现了大量的“IllegalMonitorStateException”异常,暂时还分析不了出错的原因
通过阻塞队列实现线程间通信