多线程的同步问题

看一个例子,背景是,银行卡里有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

 

posted @ 2018-05-16 16:05  无名草110  阅读(140)  评论(0编辑  收藏  举报