zoukankan      html  css  js  c++  java
  • 多线程的同步问题

    看一个例子,背景是,银行卡里有1000块钱,在柜台取800块钱,在提款机取800块钱,理论上来说,这个是不允许的

    看看实现代码

     1 package test;
     2 
     3 public class FetchMoney {
     4 
     5     public static void main(String[] args) {
     6 
     7         Bank bank = new Bank();
     8 
     9         MoneyThread thread1 = new MoneyThread(bank); // 柜台手续线程
    10         MoneyThread thread2 = new MoneyThread(bank); // 自助机手续线程
    11 
    12         thread1.start();
    13         thread2.start();
    14     }
    15 
    16 }
    17 
    18 class Bank {
    19     private int money = 1000;
    20 
    21     public int getMoney(int money) {
    22 
    23         if(money < 0) {
    24             return -1;
    25         }
    26 
    27         if(money > this.money) {
    28             return -2;
    29         }
    30 
    31         try {
    32             Thread.sleep(1000); // 取钱前的一些准备工作
    33         } catch (Exception e) {
    34             e.printStackTrace();
    35         }
    36 
    37         this.money -= money;
    38         return money;
    39     }
    40 }
    41 
    42 class MoneyThread extends Thread {
    43 
    44     private Bank bank;
    45 
    46     public MoneyThread(Bank bank) {
    47         this.bank = bank;
    48     }
    49 
    50     @Override
    51     public void run() {
    52         System.out.println(bank.getMoney(800));
    53     }
    54 }
    
    
    

    执行的结果是

    800
    800
    
    Process finished with exit code 0

    1000块钱的余额居然真的取出2次800块钱了

    问题的根源在于,2个线程会同时访问一个实例的某个成员变量,2条线程判断条件时成员变量的值均可能是还没取钱时候的值

    要解决这个问题,我们可以这么想,取钱的时候(即调getMoney方法的时候),只允许1条线程访问,就解决了

    代码如下:

     1 package test;
     2 
     3 public class FetchMoney {
     4 
     5     public static void main(String[] args) {
     6 
     7         Bank bank = new Bank();
     8 
     9         MoneyThread thread1 = new MoneyThread(bank); // 柜台手续线程
    10         MoneyThread thread2 = new MoneyThread(bank); // 自助机手续线程
    11 
    12         thread1.start();
    13         thread2.start();
    14 
    15 
    16     }
    17 
    18 }
    19 
    20 class Bank {
    21     private int money = 1000;
    22 
    23     public synchronized int getMoney(int money) {
    24 
    25         if(money < 0) {
    26             return -1;
    27         }
    28 
    29         if(money > this.money) {
    30             return -2;
    31         }
    32 
    33         try {
    34             Thread.sleep(1000); // 取钱前的一些准备工作
    35         } catch (Exception e) {
    36             e.printStackTrace();
    37         }
    38 
    39         this.money -= money;
    40         return money;
    41     }
    42 
    43     public int getMoney2(int money) {
    44 
    45         synchronized(this) {
    46             if (money < 0) {
    47                 return -1;
    48             }
    49 
    50             if (money > this.money) {
    51                 return -2;
    52             }
    53 
    54             try {
    55                 Thread.sleep(1000); // 取钱前的一些准备工作
    56             } catch (Exception e) {
    57                 e.printStackTrace();
    58             }
    59 
    60             this.money -= money;
    61         }
    62         return money;
    63     }
    64 }
    65 
    66 class MoneyThread extends Thread {
    67 
    68     private Bank bank;
    69 
    70     public MoneyThread(Bank bank) {
    71         this.bank = bank;
    72     }
    73 
    74     @Override
    75     public void run() {
    76         System.out.println(bank.getMoney(800));
    77     }
    78 }
    
    
    
    

    调用getMoney或者getMoney2都可以

    结果为:

    800
    -2
    
    Process finished with exit code 0
  • 相关阅读:
    004_列表list操作
    003_字符串str的操作
    002_python基础语录
    求哈夫曼树的编码
    Python笔记(一)——打印输出
    python基础一 day33 验证客户端的合法性
    python基础一 day32 复习
    python基础一 day30 网络编程
    python基础一 day29 logging
    python基础一 day29 学习方法(课前谈心)
  • 原文地址:https://www.cnblogs.com/billmiao/p/9872209.html
Copyright © 2011-2022 走看看