首页 > 代码库 > 线程(while 和 if 剖析)

线程(while 和 if 剖析)

那存钱取钱为例:

  要求实现一次存一次取的操作 不可出现连续存或连续取;

  如果只有存钱和取钱各自只有一个线程在操作使用 if 的话可以满足要求:

  

 1 package com.thread; 2 /** 3  * 模拟同步取款的问题 4  * @author dr 5  * 6  */ 7 public class ThreadTest { 8     public static void main(String[] args) { 9         final Account account = new Account();10         //取出20011         new Thread(new Runnable() {12             @Override13             public void run() {14                 for(int i=0;i<3;i++){15                     try {16                         Thread.sleep(500);17                     } catch (InterruptedException e) {18                         // TODO Auto-generated catch block19                         e.printStackTrace();20                     }21                     account.getMoney(200);22                 }23             }24         }).start();25         //存入30026         new Thread(new Runnable() {27             @Override28             public void run() {29                 for(int i=0;i<3;i++){30                     try {31                         Thread.sleep(500);32                     } catch (InterruptedException e) {33                         // TODO Auto-generated catch block34                         e.printStackTrace();35                     }36                     account.setMoney(300);37                 }38             }39         }).start();40     }41 }42 class Account {43     44     private int balance = 1000;45     private boolean setMoney = true;46     public synchronized void getMoney(int count){47         if(setMoney){48             try {49                 this.wait();50             } catch (InterruptedException e) {51                 // TODO Auto-generated catch block52                 e.printStackTrace();53             }54         }55         int result =balance - count;56         if(result >= 0){57             balance = result;58             System.out.println(Thread.currentThread().getName()+"取出:"+count+"元,剩余:"+balance);59         }else{60             System.out.println("余额不足...");61         }62         setMoney = true;63         this.notify();64     }65     public synchronized void setMoney(int count){66             if(!setMoney){67                 try {68                     this.wait();69                 } catch (InterruptedException e) {70                     // TODO Auto-generated catch block71                     e.printStackTrace();72                 }73             }74             balance += count;75             System.out.println(Thread.currentThread().getName()+"存入:"+count+"元,剩余:"+balance);76             setMoney =  false;77             this.notify();78     }79     80 }
View Code

  但是如果存钱和取钱包含多个线程的话 if 就不行 只有使用while才能满足条件

 1 package com.thread; 2 /** 3  * 模拟同步取款的问题 4  * @author dr 5  * 6  */ 7 public class ThreadTest { 8     public static void main(String[] args) { 9         final Account account = new Account();10         //取出200 两个取钱的线程11         for(int i=0;i<2;i++){12             new Thread(new Runnable() {13                 @Override14                 public void run() {15                     for(int i=0;i<3;i++){16                         try {17                             Thread.sleep(500);18                         } catch (InterruptedException e) {19                             // TODO Auto-generated catch block20                             e.printStackTrace();21                         }22                         account.getMoney(200);23                     }24                 }25             }).start();26         }27         //存入300 两个存钱的线程28         for(int i=0;i<2;i++){29             new Thread(new Runnable() {30                 @Override31                 public void run() {32                     for(int i=0;i<3;i++){33                         try {34                             Thread.sleep(500);35                         } catch (InterruptedException e) {36                             // TODO Auto-generated catch block37                             e.printStackTrace();38                         }39                         account.setMoney(300);40                     }41                 }42             }).start();43         }44     }45 }46 class Account {47     48     private int balance = 1000;49     //先存钱50     private boolean setMoney = true;51     public synchronized void getMoney(int count){52         while(setMoney){53             try {54                 this.wait();55             } catch (InterruptedException e) {56                 // TODO Auto-generated catch block57                 e.printStackTrace();58             }59         }60         int result =balance - count;61         if(result >= 0){62             balance = result;63             System.out.println(Thread.currentThread().getName()+"取出:"+count+"元,剩余:"+balance);64         }else{65             System.out.println("余额不足...");66         }67         setMoney = true;68         this.notifyAll();69     }70     public synchronized void setMoney(int count){71             while(!setMoney){72                 try {73                     this.wait();74                 } catch (InterruptedException e) {75                     // TODO Auto-generated catch block76                     e.printStackTrace();77                 }78             }79             balance += count;80             System.out.println(Thread.currentThread().getName()+"存入:"+count+"元,剩余:"+balance);81             setMoney =  false;82             this.notifyAll();83     }84     85 }
View Code

分析:
  有A、B、C、D四个线程 AB存钱线程,CD取钱线程,使用if的时候,假设A执行,看标志无需wait 执行完成后 改标志为 取 ,A B 都先获得执行权 但状态不符合,

  处于等待状态 A B 无执行权, C获得执行权后 执行完成后 更改状态为存 同时唤醒 A ,D获得执行权也处于等待状态。

  现在只有A有执行权  A执行完成后 更改标志 先唤醒 B,B此时无需检查标志了紧接执行存款 从而导致 出现连续两次 取款的情形

  使用while的时候 ,虽然B被唤醒 但经while(flag) 又会 检查标志 使其处于等待状态 使用while 要使用notifyAll 否则会出现全部等待状态

线程(while 和 if 剖析)