1 package day2_4;
2
3 import java.util.concurrent.locks.ReentrantLock;
4
5 /**
6 * 银行有一个账户。
7 * 两个储户向同一个账户里存钱,每个储户都是存3000元,分三次,每次存1000。
8 * 每次存完打印账户余额
9 *
10 * 分析:
11 * 1.是多线程问题吗? 是,两个储户线程
12 * 2.是否有共享数据? 有,同一个账户(或账户余额)
13 * 3.是否有线程安全问题? 有
14 * 4.如何解决线程安全问题? 同步机制:有三种方式
15 *
16 *
17 * @Author Tianhao
18 * @create 2021-02-05-18:21
19 */
20 public class AccountTest {
21 public static void main(String[] args) {
22 Account acct = new Account(0);
23 Customer c1 = new Customer(acct);
24 Customer c2 = new Customer(acct);
25 c1.setName("客户1");
26 c2.setName("客户2");
27 c1.start();
28 c2.start();
29 }
30
31 }
32
33 //账号
34 class Account {
35 //余额
36 private double balance = 0;
37
38 public Account(double balance) {
39 this.balance = balance;
40 }
41
42 private ReentrantLock lock = new ReentrantLock();
43
44 //存钱操作
45 //这里虽然线程类是继承Thread方式创建,但同步方法上没有static修饰
46 //因为这个方法所在Account类的对象acct是多个线程共享的,就可以用this作为同步监视器
47 //解决线程安全问题:方式一:使用同步方法
48 // public synchronized void deposit(double amt) {
49 // if (amt > 0) {
50 // balance += amt;
51 // try {
52 // Thread.sleep(1000);
53 // } catch (InterruptedException e) {
54 // e.printStackTrace();
55 // }
56 // System.out.println( Thread.currentThread().getName() + ":存钱成功。余额:" + balance);
57 // }
58 // }
59
60 //解决线程安全问题:方式二:使用同步代码块
61 public void deposit(double amt) {
62 synchronized (this) {
63 if (amt > 0) {
64 balance += amt;
65 try {
66 Thread.sleep(1000);
67 } catch (InterruptedException e) {
68 e.printStackTrace();
69 }
70 System.out.println(Thread.currentThread().getName() + ":存钱成功。余额:" + balance);
71 }
72 }
73 }
74
75
76 //解决线程安全问题:方式三:使用lock方法
77 // public synchronized void deposit(double amt) {
78 // try {
79 // lock.lock();
80 // if (amt > 0) {
81 // balance += amt;
82 // try {
83 // Thread.sleep(1000);
84 // } catch (InterruptedException e) {
85 // e.printStackTrace();
86 // }
87 // System.out.println( Thread.currentThread().getName() + ":存钱成功。余额:" + balance);
88 // }
89 // }finally {
90 // lock.unlock();
91 // }
92 // }
93
94 public double getBalance() {
95 return balance;
96 }
97 }
98 //储户
99 class Customer extends Thread{
100 private Account acct;
101 //将Account对象作为参数传入到构造器,这样就保证了创建的
102 // 每个Customer对象都是同一个Account对象
103 public Customer(Account acct) {
104 this.acct = acct;
105 }
106
107 @Override
108 public void run() {
109 for (int i = 0; i < 3; i++) {
110 acct.deposit(1000);
111 }
112 }
113 }