多線程數據髒讀實際上我們在前面已經遇到過了,就是前面同一個對象持有一把鎖比較類鎖,我們先看下髒讀的情況:
賬戶類:
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
實際上這就是併發問題,我們需要通過鎖來實現線程安全問題。