多线程尝试(一)

今天了解多线程的过程中,随手写了一个银行存钱的Demo,对于部分业务需要用到同步机制。

先看代码:

这是模拟银行账户的抽象类:

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

/**
 * @Author:KrisYu
 * @Description:银行账户
 */
public class Account {

    //账户余额
    private Double balance = 0d;

    //存钱
    public void saveMoney(Double money) {
        Double newMoney = balance + money;
        //模拟存钱需要时间
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        balance = newMoney;
    }

    //查看余额
    public Double getBalence() {
        System.out.println("还剩余额:" + balance + "元");
        return balance;
    }
}

这是把存钱的操作单独抽成一个类,用于线程操作

/**
 * @Author:KrisYu
 * @Description:存钱线程
 */
public class AddMoneyThread implements Runnable {
    private Account account;
    private Double money;

    public AddMoneyThread(Account account,Double money){
        this.account = account;
        this.money = money;
    }

    public void run() {
            account.saveMoney(money);
    }
}

最后是操作类,简历线程池,用于实现100次的线程操作

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author:KrisYu
 * @Description:存钱线程
 */
public class AccountTest {

    public static void main(String[] args) {
        Account yuAccount = new Account();
        Double money = 1d;
        AddMoneyThread addMoneyThread = new AddMoneyThread(yuAccount, money);
        ExecutorService executorService = Executors.newFixedThreadPool(100);

        for (int i = 0; i < 100; i++) {
            executorService.execute(new AddMoneyThread(yuAccount, money));
        }
        executorService.shutdown();
        //确保线程关闭完全,不然的话是死循环
        while (!executorService.isTerminated()) {
        }
        yuAccount.getBalence();

    }
}

执行100词存钱,每次存一元,但是惊奇的发现 打印的结果往往只有个位数甚至1元,让我们进入思考,多个线程并发运行,大多数线程都是取到了0余额然后对其加1元所以结果不在预料之内。要改正只能保证每一次存钱操作同步进行,我在这里提供三个思路

一:

直接在存钱操作上加上synchronized关键字保证saveMoney()方法上锁,同一时刻最多有一个线程来执行这个方法。

//存钱
public synchronized void saveMoney(Double money) {
    Double newMoney = balance + money;
    //模拟存钱需要时间
    try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    balance = newMoney;
}

二:直接再重写的run方法给Account对象上锁,保证对这个对象最多有一个线程来进入对象修改信息

public void run() {
    synchronized (account) {
        account.saveMoney(money);
    }
}

三:在saveMoney()方法中上重入锁把存钱相关代码上锁,并在执行完成后解锁

//重入锁
private Lock accountLock = new ReentrantLock();

//存钱
public synchronized void saveMoney(Double money) {
    accountLock.lock();
    try {
        Double newMoney = balance + money;
        //模拟存钱需要时间
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        balance = newMoney;
    } finally {
        accountLock.unlock();
    }
}

好,今天写到这里,欢迎大家在评论区回答你最喜欢的同步方式,并写上原因。

参考文献:骆昊的博客




阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页