Java多线程练习--取钱
1.需求:
// 小明和小红是一对夫妻,他们有一个共同的账户,余额是10万元,模拟2人同时去取钱10万。
// 分析:
// 1:需要提供一个账户类,创建一个账户对象代表2个人的共享账户。
// 2:需要定义一个线程类,线程类可以处理账户对象。
// 3:创建2个线程对象,传入同一个账户对象。
// 4:启动2个线程,去同一个账户对象中取钱10万。
目录
一.同步代码块
二.同步方法
三.lock锁
一.同步代码块
public class Account { private String cardId; private double money; // 余额 关键信息 public Account() { } public Account(String cardId, double money) { this.cardId = cardId; this.money = money; } public String getCardId() { return cardId; } public void setCardId(String cardId) { this.cardId = cardId; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; }// // 100个线程人// public static void run(){// synchronized (Account.class){//// }// } /** 小明 小红 */ public void drawMoney(double money) { // 1、拿到是谁来取钱 String name = Thread.currentThread().getName(); // 同步代码块 // 小明 小红 // this == acc 共享账户 synchronized (this) { // 2、判断余额是否足够 if(this.money >= money){ // 钱够了 System.out.println(name+"来取钱,吐出:" + money); // 更新余额 this.money -= money; System.out.println(name+"取钱后,余额剩余:" + this.money); }else{ // 3、余额不足 System.out.println(name+"来取钱,余额不足!"); } } }}public class Account { private String cardId; private double money; // 余额 关键信息 public Account() { } public Account(String cardId, double money) { this.cardId = cardId; this.money = money; } public String getCardId() { return cardId; } public void setCardId(String cardId) { this.cardId = cardId; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; }// // 100个线程人// public static void run(){// synchronized (Account.class){//// }// } /** 小明 小红 */ public void drawMoney(double money) { // 1、拿到是谁来取钱 String name = Thread.currentThread().getName(); // 同步代码块 // 小明 小红 // this == acc 共享账户 synchronized (this) { // 2、判断余额是否足够 if(this.money >= money){ // 钱够了 System.out.println(name+"来取钱,吐出:" + money); // 更新余额 this.money -= money; System.out.println(name+"取钱后,余额剩余:" + this.money); }else{ // 3、余额不足 System.out.println(name+"来取钱,余额不足!"); } } }}
public class DrawThread extends Thread{ private Account acc; public DrawThread(Account acc, String name){ super(name); this.acc = acc; } @Override public void run() { // 小明 小红 : acc acc.drawMoney(100000); }}
public class TestSafeDemo { public static void main(String[] args) { // 测试线程安全问题 // 1、创建一个共享的账户对象。 Account acc = new Account("ICBC-111" , 100000); // 2、创建2个线程对象,操作同一个账户对象 new DrawThread(acc, "小明").start(); new DrawThread(acc,"小红").start(); }}
二.同步方法
public class Account { private String cardId; private double money; // 余额 关键信息 public Account() { } public Account(String cardId, double money) { this.cardId = cardId; this.money = money; } public String getCardId() { return cardId; } public void setCardId(String cardId) { this.cardId = cardId; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } /** 小明 小红this == acc */ public synchronized void drawMoney(double money) { // 1、拿到是谁来取钱 String name = Thread.currentThread().getName(); // 2、判断余额是否足够 // 小明 小红 if(this.money >= money){ // 钱够了 System.out.println(name+"来取钱,吐出:" + money); // 更新余额 this.money -= money; System.out.println(name+"取钱后,余额剩余:" + this.money); }else{ // 3、余额不足 System.out.println(name+"来取钱,余额不足!"); } }}
public class DrawThread extends Thread{ private Account acc; public DrawThread(Account acc, String name){ super(name); this.acc = acc; } @Override public void run() { // 小明 小红 : acc acc.drawMoney(100000); }}
import java.util.*;public class TestSafeDemo { public static void main(String[] args) { // 测试线程安全问题 // 1、创建一个共享的账户对象。 Account acc = new Account("ICBC-111" , 100000); // 2、创建2个线程对象,操作同一个账户对象 new DrawThread(acc, "小明").start(); new DrawThread(acc,"小红").start(); }}
三.lock锁
import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** 账户类:余额 , 卡号。 */public class Account { private String cardId; private double money; // 余额 关键信息 // final修饰后:锁对象是唯一和不可替换的,非常专业 private final Lock lock = new ReentrantLock(); public Account() { } public Account(String cardId, double money) { this.cardId = cardId; this.money = money; } public String getCardId() { return cardId; } public void setCardId(String cardId) { this.cardId = cardId; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } /** 小明 小红 */ public void drawMoney(double money) { // 1、拿到是谁来取钱 String name = Thread.currentThread().getName(); // 2、判断余额是否足够 // 小明 小红 lock.lock(); // 上锁 try { if(this.money >= money){ // 钱够了 System.out.println(name+"来取钱,吐出:" + money); // 更新余额 this.money -= money; System.out.println(name+"取钱后,余额剩余:" + this.money); }else{ // 3、余额不足 System.out.println(name+"来取钱,余额不足!"); } } finally { lock.unlock(); // 解锁 } }}
public class DrawThread extends Thread{ private Account acc; public DrawThread(Account acc, String name){ super(name); this.acc = acc; } @Override public void run() { // 小明 小红 : acc acc.drawMoney(100000); }}
public class TestSafeDemo { public static void main(String[] args) { // 测试线程安全问题 // 1、创建一个共享的账户对象。 Account acc = new Account("ICBC-111" , 100000); // 2、创建2个线程对象,操作同一个账户对象 new DrawThread(acc, "小明").start(); new DrawThread(acc,"小红").start(); }}