首页 > 代码库 > 多线程总结五:线程通信(一)

多线程总结五:线程通信(一)

当线程在程序中运行时,线程的调度具有一定的透明性,程序通常无法准确控制线程的轮换执行,Java提供了一些机制来保证线程协调运行。

1、传统的线程通信借助Object类提供的wait()、notify()和notifyAll()三个方法,这三个方法必须由同步监视器对象来调用。
a、wait():导致当前线程等待,直到其他线程调用该同步监视器的notify()方法或notifyAll()方法来唤醒该线程;
b、notify():唤醒在此同步监视器上等待的单个线程;
c、notifyAll():唤醒在此同步监视器上等待的所有线程;

2、模拟情景:系统中有两个线程,分别代表存款者和取款者。系统要求存款者和取款者不断重复存款和取款的动作,而且要求每当存款者将钱存入指定账户后,取款者就立即取出该笔钱。不允许存款者连续两次存钱,也不允许取钱者连续两次取钱。

  1 /**  2  * @Title: Account3.java   3  * @Package    4  * @author 任伟  5  * @date 2014-12-8 下午6:50:34   6  * @version V1.0    7  */  8   9 /** 10  * @ClassName: Account3 11  * @Description: 线程安全Account类,提供存钱和取钱的操作 12  * @author 任伟 13  * @date 2014-12-8 下午6:50:34 14  */ 15 public class Account3 { 16     private String accountNo; // 账户编号 17     private double balance; // 账户余额 18     private boolean flag = false; // 表示账户中是否已有存款的骑标 19  20     public String getAccountNo() { 21         return accountNo; 22     } 23  24     public void setAccountNo(String accountNo) { 25         this.accountNo = accountNo; 26     } 27  28     public double getBalance() { 29         return balance; 30     } 31  32     public Account3() { 33         super(); 34     } 35  36     public Account3(String accountNo, double balance) { 37         super(); 38         this.accountNo = accountNo; 39         this.balance = balance; 40     } 41  42     public boolean equals(Object anObject) { 43         if (this == anObject) 44             return true; 45         if (anObject != null && anObject.getClass() == Account.class) { 46             Account target = (Account) anObject; 47             return target.getAccountNo().equals(accountNo); 48         } 49         return false; 50     } 51  52     public int hashCode() { 53         return accountNo.hashCode(); 54     } 55  56     // 取钱操作 57     public synchronized void draw(double drawAmount) { 58         try { 59             if (!flag) {//如果flag为假,表明账户中还没有人存钱进去,取钱方法阻塞 60                 wait(); 61             } else {//否则就进行取钱操作 62                 if (balance >= drawAmount) { 63                     System.out.println(Thread.currentThread().getName() 64                             + "取钱成功,吐出钞票:" + drawAmount); 65                     try { 66                         Thread.sleep(1); 67                     } catch (InterruptedException e) { 68                         e.printStackTrace(); 69                     } 70                     balance -= drawAmount; 71                     System.out.println("余额为:" + balance); 72                 } else { 73                     System.out.println(Thread.currentThread().getName() 74                             + "取钱失败!余额不足!"); 75                 } 76                 //将账户是否已有存款的旗标设为false 77                 flag = false; 78                 //唤醒其他进程 79                 notifyAll(); 80             } 81         } catch (Exception e) { 82             e.printStackTrace(); 83         } 84     } 85      86     //存钱操作 87     public synchronized void deposit(double depositAmount){ 88         try{ 89             if(flag){//如果flag为真,表明账户中已有人存钱进去,存钱方法阻塞 90                 wait(); 91             }else{ 92                 //执行存款操作 93                 System.out.println(Thread.currentThread().getName()+" 存款:" +depositAmount); 94                 balance += depositAmount; 95                 System.out.println("账户余额为:" + balance); 96                 //将账户是否已有存款的旗标设为true 97                 flag=true; 98                 notifyAll(); 99                 100             }101         }catch (Exception e) {102             e.printStackTrace();103         }104     }105 }
Account3
 1 /** 2  * @Title: DrawDepositTest3.java  3  * @Package   4  * @author 任伟 5  * @date 2014-12-9 下午2:09:38  6  * @version V1.0   7  */ 8  9 /** 10  * @ClassName: DrawDepositTest3 11  * @Description: 测试存款和取款线程12  * @author 任伟13  * @date 2014-12-9 下午2:09:38  14  */15 public class DrawDepositTest3 {16     public static void main(String[] args) {17         Account3 acct = new Account3("1234567", 0);18         new DrawThread3("取钱者", acct, 800).start();19         new DepositThread3("存钱者甲", acct, 800).start();20         new DepositThread3("存钱者乙", acct, 800).start();21         new DepositThread3("存钱者丙", acct, 800).start();22     }23 }24 25 //取款线程26 class DrawThread3 extends Thread{27     private Account3 account;    //模拟用户账户28     private double drawAmount;  //取钱数29     30     public DrawThread3(String name, Account3 account, double drawAmount) {31         super(name);32         this.account = account;33         this.drawAmount = drawAmount;34     }35     36     //重复100次执行取钱操作37     public void run(){38         for(int i=0; i<100; i++){39             account.draw(drawAmount);40         }41     }    42 }43 44 //春款线程45 class DepositThread3 extends Thread{46     private Account3 account;    //模拟用户账户47     private double depositAmount;  //存钱数48     49     public DepositThread3(String name, Account3 account, double depositAmount) {50         super(name);51         this.account = account;52         this.depositAmount = depositAmount;53     }54     55     //重复100次执行存钱操作56     public void run(){57         for(int i=0; i<100; i++){58             account.deposit(depositAmount);59         }60     }61     62     63 }
DrawDepositTest3

Result


如图所示的阻塞并不是死锁,取钱者线程已经执行结束,而存款者线程只是在等待其他线程来取钱而已,并不是等待其他线程释放同步监视器。

多线程总结五:线程通信(一)