多线程数据脏读实际上我们在前面已经遇到过了,就是前面同一个对象持有一把锁比较类锁,我们先看下脏读的情况:
账户类:
package com.ck.thread;
import java.math.BigDecimal;
package com.ck.thread;
import java.math.BigDecimal;
public class Account {
private String name;
private BigDecimal balance = new BigDecimal("0");
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getBalance() {
return balance;
}
public void setBalance(BigDecimal balance) {
this.balance = balance;
}
public synchronized void add(BigDecimal amount) {
System.out.println(name + ", 开始充值,充值前余额: " + balance);
try {
Thread.sleep(2000);
balance = balance.add(amount);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + ", 结束充值,充值后余额: " + balance);
}
public void print() {
System.out.println(name + ", 当前余额: " + balance);
}
}
我们在写个充值的线程类:
package com.ck.thread;
import java.math.BigDecimal;
public class CzThread extends Thread{
private Account account;
public CzThread(Account account) {
this.account = account;
}
@Override
public void run() {
account.add(new BigDecimal("100"));
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
查询余额:
package com.ck.thread;
public class PrintThread extends Thread{
private Account account;
public PrintThread(Account account) {
this.account = account;
}
@Override
public void run() {
account.print();
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
用户先充值再查询余额:
package com.ck.thread;
import java.math.BigDecimal;
public class MainThread {
public static void main(String[] args) throws InterruptedException {
Account account1 = new Account();
account1.setName("张三");
account1.setBalance(new BigDecimal("100"));
Thread t1 = new CzThread(account1);
t1.start();
Thread.sleep(500);
Thread t2 = new PrintThread(account1);
t2.start();
}
}
看下结果:
张三, 开始充值,充值前余额: 100
张三, 当前余额: 100
张三, 结束充值,充值后余额: 200
这时候就出现了脏数据,因为余额应该是200,我们修改下:
package com.ck.thread;
import java.math.BigDecimal;
public class Account {
private String name;
private BigDecimal balance = new BigDecimal("0");
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getBalance() {
return balance;
}
public void setBalance(BigDecimal balance) {
this.balance = balance;
}
public synchronized void add(BigDecimal amount) {
System.out.println(name + ", 开始充值,充值前余额: " + balance);
try {
Thread.sleep(2000);
balance = balance.add(amount);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + ", 结束充值,充值后余额: " + balance);
}
/**注意这儿加锁了*/
public synchronized void print() {
System.out.println(name + ", 当前余额: " + balance);
}
}
我们将获取余额也加锁了,我们看下运行结果:
张三, 开始充值,充值前余额: 100
张三, 结束充值,充值后余额: 200
张三, 当前余额: 200
实际上这就是并发问题,我们需要通过锁来实现线程安全问题。