import java.util.concurrent.locks.ReentrantLock;
/**
* 演示案例:銀行有一個帳戶
* 有兩個存戶分別向同一個帳戶存3000元,每次存1000,存3次。
* 每次存完輸出帳戶餘額
* @author sunwc
* @create 2023-03-24 下午 12:23
*/
public class ConcurrentAccount {
public static void main(String[] args) {
// 帳戶為共享資源,只new一次
Account account = new Account();
Depositor depositor = new Depositor(account);
Thread t1 = new Thread(depositor);
Thread t2 = new Thread(depositor);
t1.setName("存戶1");
t2.setName("存戶2");
t1.start();
t2.start();
}
}
/**
* 帳戶類
*/
class Account {
/**
* 存款餘額
*/
private double balance;
/**
* 存入金額並輸出帳戶餘額
* @param amount
*/
synchronized void deposit(int amount) {// 同步鎖默認為this
if (amount > 0) {
this.balance += amount;
// 看會不會增加執行緒不安全問題
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 帳戶餘額:" + this.balance);
}
}
}
/**
* 存戶類
*/
class Depositor implements Runnable {
private Account account;
public Depositor(Account account) {
this.account = account;
}
/**
* 鎖,設置執行緒先進先出
*/
private ReentrantLock reentrantLock = new ReentrantLock(true);
@Override
public void run() {
// 每個存戶 每次存1000、存3次
for (int i = 0; i < 3; i++) {
try {
reentrantLock.lock();
// 存1000
account.deposit(1000);
} finally {
reentrantLock.unlock();
}
}
}
}
輸出結果:
存戶1 帳戶餘額:1000.0
存戶2 帳戶餘額:2000.0
存戶1 帳戶餘額:3000.0
存戶2 帳戶餘額:4000.0
存戶1 帳戶餘額:5000.0
存戶2 帳戶餘額:6000.0
/**
* @author sunwc
* @create 2023-03-24 下午 12:52
*/
public class ConcurrentAccount2 {
public static void main(String[] args) {
Depositor2 depositor1 = new Depositor2();
Depositor2 depositor2 = new Depositor2();
depositor1.setName("存戶1");
depositor2.setName("存戶2");
depositor1.start();
depositor2.start();
}
}
/**
* 帳戶類
*/
class Account2 {
/**
* 存款餘額
*/
private double balance;
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
/**
* 存戶類
*/
class Depositor2 extends Thread {
/**
* 帳戶(共享資源)
*/
private static Account2 account;
/**
* constrctor在創建存戶時一併創建帳戶
*/
public Depositor2() {
synchronized (Depositor.class) {
if (account == null) {
account = new Account2();
}
}
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
// 存1000
synchronized (Depositor2.class) {
deposit(1000);
}
}
}
/**
* 存錢操作
* @param amount
*/
private void deposit(int amount) {
if (amount > 0) {
// 先取得餘額
double currnetBalance = account.getBalance();
// 增加存款金額
currnetBalance += amount;
account.setBalance(currnetBalance);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 存錢成功,帳戶餘額:" + account.getBalance());
}
}
}
輸出結果:
存戶1 存錢成功,帳戶餘額:1000.0
存戶2 存錢成功,帳戶餘額:2000.0
存戶2 存錢成功,帳戶餘額:3000.0
存戶1 存錢成功,帳戶餘額:4000.0
存戶1 存錢成功,帳戶餘額:5000.0
存戶2 存錢成功,帳戶餘額:6000.0
我們在下面兩篇文章已經了解到解決執行緒不安全的兩種方式
有關透過鎖 Lock 解決執行緒不安全問題,可以參考我的另一篇文章 Java - Lock - 解決執行緒不安全
有關透過實現類 implements interface Runnable 達成 Multi-threading,可以參考我的另一篇文章 Java - Thread 執行緒(二) - interface Runnable
本篇文章是舉例另一個可能會造成執行緒不安全的現實例子,能夠對於同步的機制更加印象深刻