• 线程(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         //取出200
    11         new Thread(new Runnable() {
    12             @Override
    13             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 block
    19                         e.printStackTrace();
    20                     }
    21                     account.getMoney(200);
    22                 }
    23             }
    24         }).start();
    25         //存入300
    26         new Thread(new Runnable() {
    27             @Override
    28             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 block
    34                         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 block
    52                 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 block
    71                     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                 @Override
    14                 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 block
    20                             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                 @Override
    31                 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 block
    37                             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 block
    57                 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 block
    76                     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 否则会出现全部等待状态

  • 相关阅读:
    redis-client和redis-template存储的key的格式不一样
    dubbo+zookeeper基础
    java面试题1
    Spring线程池(异步、同步)
    Java并发多线程
    Java并发-并发工具类JUC
    Java并发面试题
    ActiveMQ
    一键部署springboot到Docker
    Quartz任务调度学习
  • 原文地址:https://www.cnblogs.com/Wen-yu-jing/p/4084137.html
Copyright © 2020-2023  润新知