[Java手撕]线程安全的转账

首先来看线程不安全的转账#

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() {
                @Override
                public 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);
        }

    }
}

image

线程安全的转账#

竞争太激烈,所有线程都在抢同一把银行锁

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() {
                @Override
                public 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);
        }

    }
}

image

线程安全的转账升级版#

分散锁到各个账户上去,每个线程只要取得两个账户上的锁即可,
要注意按顺序获取锁,否则会死锁

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() {
                @Override
                public 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);
        }
    }
}

image

作者:Esofar

出处:https://www.cnblogs.com/DCFV/p/18374525

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Duancf  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示