Java多线程:同步的案例

本文记录Java多线程同步的案例。

背景:银行(Bank)里面有多个账户,将两个账户进行转账(调用Bank对象的transfer方法),这在个过程中,银行里钱的总额保持不变。

客户端:开启多个线程进行转账操作

import java.util.Random;

/**
 * UnsynchBankTest
 */
public class UnsynchBankTest {

    public static final int NACCOUNTS = 100;
    public static final double INITIAL_BALANCE = 1000;
    public static final double MAX_AMOUNT = 1000;
    public static final int DELAY = 10;

    public static void main(String[] args) {
        //Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
        // BankWithConditionClock bank = new BankWithConditionClock(NACCOUNTS, INITIAL_BALANCE);
        BankInLockTest bank = new BankInLockTest(NACCOUNTS, INITIAL_BALANCE);
        for (int i=0; i< NACCOUNTS; i++){
            int fromAccount = i;
            Runnable r = () ->{
                try{
                    while(true){
                        int toAccount = (int)(bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int)(DELAY * Math.random()));
                    }
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            };
            Thread t = new Thread(r);
            t.start();
        }


    }
}

方案一:使用使用锁的方案进行同步

import java.util.Arrays;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Bank
 */
public class Bank {

    /**
     * 多个银行账户
     */
    private final double[] accounts;
    // 使每一个对象有自己的ReentrantLock对象
    private Lock bankLock = new ReentrantLock();

    public Bank(int n, double initialBalance){
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    /**
     * 银行交易
     * @param from
     * @param to
     * @param amount
     */
    public void transfer(int from, int to, double amount){
        bankLock.lock();
        try{
            if(accounts[from]<amount) return;
            System.out.println(Thread.currentThread());
            accounts[from] -= amount;
            System.out.printf(" %10.2f from %d to %d", amount, from , to);
            accounts[to] += amount;
            System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
        }finally{
            bankLock.unlock();
        }
    }

    /**
     * 获取银行总钱数
     * @return
     */
    public double getTotalBalance(){
        double sum = 0;
        for (double a : accounts) {
            sum += a;
        }
        return sum;
    }

    public int size(){
        return accounts.length;
    }


}

方案二:使用锁对象和条件对象

当不满足转账条件的时候,将线程等待,直到满足条件再执行。

import java.util.Arrays;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 * BankWithConditionClock
 */
public class BankWithConditionClock {

    /**
     * 多个银行账户
     */
    private final double[] accounts;
    // 使每一个对象有自己的ReentrantLock对象
    private Lock bankLock;

    private Condition sufficientFunds;

    public BankWithConditionClock(int n, double initialBalance){
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
        bankLock = new ReentrantLock();
        sufficientFunds = bankLock.newCondition();
    }

    /**
     * 银行交易
     * @param from
     * @param to
     * @param amount
     * @throws InterruptedException
     */
    public void transfer(int from, int to, double amount) throws InterruptedException{
        bankLock.lock();
        try{
            // 加条件锁
            while(accounts[from]<amount) {
                sufficientFunds.await();
            }
            System.out.println(Thread.currentThread());
            accounts[from] -= amount;
            System.out.printf(" %10.2f from %d to %d", amount, from , to);
            accounts[to] += amount;
            System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
            // 唤醒处于等待的其他所有线程
            sufficientFunds.signalAll();
        }finally{
            bankLock.unlock();
        }
    }

    /**
     * 获取银行总钱数
     * @return
     */
    public double getTotalBalance(){
        double sum = 0;
        for (double a : accounts) {
            sum += a;
        }
        return sum;
    }

    public int size(){
        return accounts.length;
    }
}

方案三:使用synchronized

import java.util.Arrays;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * BankInLockTest
 */
public class BankInLockTest {

    /**
     * 多个银行账户
     */
    private final double[] accounts;

    public BankInLockTest(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }

    /**
     * 银行交易
     * 
     * @param from
     * @param to
     * @param amount
     * @throws InterruptedException
     */
    public synchronized void transfer(int from, int to, double amount) throws InterruptedException{
        // 加条件锁
        while (accounts[from] < amount) {
            wait();
        }
        System.out.println(Thread.currentThread());
        accounts[from] -= amount;
        System.out.printf(" %10.2f from %d to %d", amount, from, to);
        accounts[to] += amount;
        System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
        notifyAll();
    }

    /**
     * 获取银行总钱数
     * 
     * @return
     */
    public double getTotalBalance() {
        double sum = 0;
        for (double a : accounts) {
            sum += a;
        }
        return sum;
    }

    public int size() {
        return accounts.length;
    }
}
原创文章 161 获赞 19 访问量 6万+

猜你喜欢

转载自blog.csdn.net/hefrankeleyn/article/details/102546235