1- 线程安全问题
线程安全:多个线程操作同一个共享资源的时候可能出现线程安全问题。
/**
先模拟一个线程安全问题的案例:转账功能。
分析:整存整取。
(1)定义一个账户(余额,卡号)。
(2)定义一个取钱的线程类
(3)创建一个账户对象,创建2个线程对象,去这个账户对象取钱10000
小结:
多个线程操作同一个共享资源的时候可能出现线程安全问题。
*/
public class ThreadSave {
public static void main(String[] args) {
// 1.创建一个共享资源:是一个账户对象。这个对象必须只有一个。
Account acc = new Account("ICBC-110", 10000 );
// 2.创建2个线程对象代表小明和小红
DrawThread xiaoMing = new DrawThread("小明",acc);
xiaoMing.start();
DrawThread xiaoRed = new DrawThread("小红",acc);
xiaoRed.start();
}
}
/**
取钱的线程类。
*/
public class DrawThread extends Thread {
// 定义一个成员变量接收账户对象
private Account acc;
public DrawThread(String name , Account acc){
super(name);
this.acc = acc;
}
@Override
public void run() {
// 去账户acc中取钱
acc.drawMoney(10000);
}
}
/**
* 账户对象:
*/
public class Account {
private String cardId ;
private double money ; // 余额
public Account() {
}
public Account(String cardId, double money) {
this.cardId = cardId;
this.money = money;
}
// 小明和小红都到这里来了
public void drawMoney(double money) {
// 1.先拿到是谁来取钱:拿到当前线程的名字即可,名字是谁就是谁来取钱
String name = Thread.currentThread().getName();
// 2.判断余额是否足够
if(this.money >= money){
// 钱够了
System.out.println(name+"来取钱,余额足够,吐出:"+money);
// 3.更新余额
this.money -= money;
System.out.println(name+"取钱后剩余:"+this.money);
}else{
// 钱不够
System.out.println(name+"来取钱,余额不足");
}
}
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;
}
}
2-线程同步方式
同步代码块
/**
* 账户对象:
*/
public class Account {
private String cardId ;
private double money ; // 余额
public Account() {
}
public Account(String cardId, double money) {
this.cardId = cardId;
this.money = money;
}
// 小明和小红都到这里来了
public void drawMoney(double money) {
// 1.先拿到是谁来取钱:拿到当前线程的名字即可,名字是谁就是谁来取钱
String name = Thread.currentThread().getName();
// 2.判断余额是否足够 : 和小红
synchronized (this){ // this == acc
//小明
if(this.money >= money){
// 钱够了
System.out.println(name+"来取钱,余额足够,吐出:"+money);
// 3.更新余额
this.money -= money;
System.out.println(name+"取钱后剩余:"+this.money);
}else{
// 钱不够
System.out.println(name+"来取钱,余额不足");
}
}
}
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 class Account {
private String cardId ;
private double money ; // 余额
public Account() {
}
public Account(String cardId, double money) {
this.cardId = cardId;
this.money = money;
}
// 小明和小红都到这里来了
public synchronized void drawMoney(double money) {
// 1.先拿到是谁来取钱:拿到当前线程的名字即可,名字是谁就是谁来取钱
String name = Thread.currentThread().getName();
// 2.判断余额是否足够 : 和小红
//小明
if(this.money >= money){
// 钱够了
System.out.println(name+"来取钱,余额足够,吐出:"+money);
// 3.更新余额
this.money -= money;
System.out.println(name+"取钱后剩余:"+this.money);
}else{
// 钱不够
System.out.println(name+"来取钱,余额不足");
}
}
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 class Account {
private String cardId ;
private double money ; // 余额
// 创建一把锁对象:必须保证这个对象唯一
private final Lock lock = new ReentrantLock();
public Account() {
}
public Account(String cardId, double money) {
this.cardId = cardId;
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);
// 3.更新余额
this.money -= money;
System.out.println(name+"取钱后剩余:"+this.money);
}else{
// 钱不够
System.out.println(name+"来取钱,余额不足");
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock(); // 解锁操作!
}
}
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;
}
}