假设现在系统有两个线程,这两个线程分别代表存款者和取钱者——现在假设系统有一种特殊的要求,系统要求存款者和取钱者不断地重复存款、取钱的动作。而且要求每当存款者将钱存入指定账户后,取钱者就立即取出该笔钱。不允许存款者连续两次存钱,也不允许取钱者连续两次取钱。
为了实现这种功能,可以借助Object类提供的wait()、notify()、notifyAll() 3 个方法,这3个方法并不属于Thread类,而是属于Object类。但这3 个方法必须由同步监视器对象来调用,这可分以下两种情况:
1、对于使用synchronized修饰的同步方法,因为该类的默认实例是(this)就是同步监视器。所以可以在同步方法中直接调用这3个方法。
2、对于使用synchronized修饰的同步代码块,同步监视器是synchronized后括号里的对象,所以必须使用该对象调用这3个方法。
关于这3个方法的解释如下:
wait():导致当前线程等待,直到其他线程调用该同步监视器的notify()方法或notifyAll()方法来唤醒该线程。该wait()方法有三种形式——无时间参数的wait(一直等待,知道其他线程通知),带毫秒参数的wait和带毫秒、毫微妙参数的wait(这两种方法都是等待指定时间后自动苏醒) 调用wait方法的当前线程会释放对该同步监视器的锁定。
notify():唤醒在次同步监视器上等待的单个线程。如果所有的线程都在此同步监视器上等待,则会选择唤醒其中一个线程。选择是任意的。只有当前线程放弃对该同步监视器的锁定后(使用wait方法),才可以执行被唤醒的线程。
notifyAll():唤醒在此同步监视器上等待的所有线程。只有当前线程放弃对同步监视器的锁定后,才可以执行被唤醒的线程。
1 public class DrawTest{ 2 public static void main(String[] args){ 3 Account a=new Account("刘腾",10000); 4 new DrawThread(a,100).start(); 5 new InThread(a,50).start(); 6 new InThread(a,60).start(); 7 new InThread(a,70).start(); 8 } 9 } 10 //账户类 11 class Account{ 12 private String name; 13 private double money; 14 private boolean flag=false; 15 16 public Account(){} 17 public Account(String name,double money){ 18 this.name=name; 19 this.money=money; 20 } 21 public double getMoney(){ 22 return money; 23 } 24 public synchronized void draw(double drawmoney){ 25 try{ 26 //如果flag为假,说明还没有人往里面存钱,所以让该线程等待。 27 if(!flag){ 28 wait(); 29 }else{ 30 System.out.println("取出钱数为:"+drawmoney+" 剩余钱数:"+(getMoney()-drawmoney)); 31 flag=false; 32 notifyAll(); 33 } 34 }catch(Exception e){System.out.println(e);} 35 } 36 public synchronized void deposit(double inmoney){ 37 try{ 38 if(!flag){ 39 System.out.println("存入钱数为:"+inmoney+" 目前的钱数为:"+(getMoney()+inmoney)); 40 flag=true; 41 notifyAll(); 42 }else{ 43 wait(); 44 } 45 }catch(Exception e){} 46 } 47 } 48 //取钱线程 49 class DrawThread extends Thread{ 50 private Account account; 51 private double drawmoney; 52 53 public DrawThread (Account account,double drawmoney){ 54 this.account=account; 55 this.drawmoney=drawmoney; 56 } 57 public void run(){ 58 for(int i=0;i<100;i++){ 59 account.draw(drawmoney); 60 } 61 } 62 } 63 class InThread extends Thread{ 64 private Account account; 65 private double inmoney; 66 67 public InThread(Account account,double inmoney){ 68 this.account=account; 69 this.inmoney=inmoney; 70 } 71 public void run(){ 72 for(int k=0;k<100;k++){ 73 account.deposit(inmoney); 74 } 75 } 76 }