多线程同步机制练习之银行存钱
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 }