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

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

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


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

你可能感兴趣的:(线程通信)