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

当线程在程序中运行时,线程的调度具有一定的透明性,程序通常无法准确控制线程的轮换执行,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


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

原文地址:https://www.cnblogs.com/renwei/p/4153207.html