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


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


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

  • 相关阅读:
    如何使用sendEmail发送邮件
    Linux curl命令详解
    linux比较两个文件是否一样(linux命令md5sum使用方法)
    strace命令用法详解
    strace用法说明
    ORA-12154 TNS无法解析指定的连接标识符
    VNC远程连接阿里云Linux服务器 图形界面
    pycharm配置Git 代码管理
    FireFox浏览器-xpath快速定位插件:Xpath Checker
    odoo 前端模板引擎 Qweb
  • 原文地址:https://www.cnblogs.com/renwei/p/4153207.html
Copyright © 2020-2023  润新知