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 }