首先来看线程不安全的转账
public class Bank {private int[] accounts;public Bank() {this.accounts = new int[10];for (int i = 0; i < 10; i++) {accounts[i] = 1000;}}public void transfer(int from, int to, int amount) {if (accounts[from] >= amount) {accounts[from] -= amount;accounts[to] += amount;}}public int total() {int count = 0;for (int i = 0; i < 10; i++) {count += accounts[i];}return count;}
}
import java.util.Random;
import java.util.concurrent.CountDownLatch;public class Main {public static void main(String[] args) {Bank bank = new Bank();Random random = new Random();CountDownLatch countDownLatch = new CountDownLatch(10000);for (int i = 0; i < 10000; i++) {new Thread(new Runnable() {@Overridepublic void run() {int from = random.nextInt(10);int to = random.nextInt(10);int amount = random.nextInt(1000);bank.transfer(from, to, amount);System.out.println(Thread.currentThread().getName() + " 从 " + from + " 转账到 " + to + " " + amount + " 元");countDownLatch.countDown();}}).start();}try {countDownLatch.await();System.out.println("银行最终总余额 = " + bank.total());} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
线程安全的转账
竞争太激烈,所有线程都在抢同一把银行锁
public class Bank {private int[] accounts;public Bank() {this.accounts = new int[10];for (int i = 0; i < 10; i++) {accounts[i] = 1000;}}public synchronized void transfer(int from, int to, int amount) {if (accounts[from] >= amount) {accounts[from] -= amount;accounts[to] += amount;}}public int total() {int count = 0;for (int i = 0; i < 10; i++) {count += accounts[i];}return count;}
}
import java.util.Random;
import java.util.concurrent.CountDownLatch;public class Main {public static void main(String[] args) {Bank bank = new Bank();Random random = new Random();CountDownLatch countDownLatch = new CountDownLatch(10000);for (int i = 0; i < 10000; i++) {new Thread(new Runnable() {@Overridepublic void run() {int from = random.nextInt(10);int to = random.nextInt(10);int amount = random.nextInt(1000);bank.transfer(from, to, amount);System.out.println(Thread.currentThread().getName() + " 从 " + from + " 转账到 " + to + " " + amount + " 元");countDownLatch.countDown();}}).start();}try {countDownLatch.await();System.out.println("银行最终总余额 = " + bank.total());} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
线程安全的转账升级版
分散锁到各个账户上去,每个线程只要取得两个账户上的锁即可,
要注意按顺序获取锁,否则会死锁
import java.util.concurrent.locks.ReentrantLock;public class Account {private int money;private ReentrantLock lock;public Account(int money){this.money = money;lock = new ReentrantLock();}public ReentrantLock getLock() {return lock;}public int getMoney() {return money;}public void sub(int money){this.money -= money;}public void add(int money){this.money += money;}
}
import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;public class Bank {private Account[] accounts;public Bank(int num){this.accounts = new Account[1000];for(int i = 0;i<num;i++){this.accounts[i] = new Account(1000);}}public void transfer(int from ,int to ,int amount){ReentrantLock lock1,lock2;if (from < to){lock1 = accounts[from].getLock();lock2 = accounts[to].getLock();}else if(from > to){lock2 = accounts[from].getLock();lock1 = accounts[to].getLock();}else{return;}synchronized (lock1){synchronized (lock2){if(accounts[from].getMoney()>=amount){accounts[from].sub(amount);accounts[to].add(amount);}}}}public int total(){int count = 0;for (int i = 0;i<this.accounts.length ;i++){count += accounts[i].getMoney();}return count;}}
import java.sql.Time;
import java.util.Random;
import java.util.concurrent.CountDownLatch;public class Main {public static void main(String[] args) {Bank bank = new Bank(1000);Random random = new Random();CountDownLatch countDownLatch = new CountDownLatch(1000);long start = System.nanoTime();for (int i = 0; i < 1000; i++) {new Thread(new Runnable() {@Overridepublic void run() {int from = random.nextInt(10);int to = random.nextInt(10);int amount = random.nextInt(1000);bank.transfer(from, to, amount);System.out.println(Thread.currentThread().getName() + " 从 " + from + " 转账到 " + to + " " + amount + " 元");countDownLatch.countDown();}}).start();}try {countDownLatch.await();long end = System.nanoTime();System.out.println("程序运行总时间 "+ (end - start)/1000000 + "毫秒");System.out.println("银行最终总余额 = " + bank.total());} catch (InterruptedException e) {throw new RuntimeException(e);}}
}