多线程同步机制2-深入理解synchronized关键字

上一节讲了关键字synchronized的基本用法。这一节我将用一个实际的例子来深入多线程同步机制的理解。

存取款改造

/**
 * Created by qianyi on 2017/9/9.
 */
public class FetchOperationMoney {
    public static void main(String[] args) {
        Bank bank = new Bank();
        Thread t1 = new AtmSaveMoney(bank);//ATM存钱
        Thread t2 = new GuitaiSaveMoney(bank);//柜台存钱
        Thread t3 = new AtmFetchMoney(bank);//ATM取钱
        Thread t4 = new GuiTaiFetchMoney(bank);//柜台取钱
        //分别启动四个线程去对账户进行操作
        bank.searchBalance();//访问没有加synchronized的方法,
        t1.start();
        bank.searchBalance();//访问没有加synchronized的方法,
        t2.start();
        bank.searchBalance();//访问没有加synchronized的方法,
        t3.start();
        bank.searchBalance();//访问没有加synchronized的方法,
        t4.start();
        bank.searchBalance();//访问没有加synchronized的方法,
    }
}

/**
 * 银行账户
 */
class Bank {
    /**
     * 账户余额
     */
    private int balance = 1000;

    /**
     * 操作取钱的方法
     *
     * @param number 取钱金额
     * @return
     */
    public synchronized int fetchMoney(int number, String channel) {
        System.out.println("取款开始:");
        System.out.println("取款来自渠道:" + channel + ",账户操作前余额:" + balance);
        System.out.println("账户取款金额:" + number);
        if (number < 0) {
            return -1;
        } else if (number > balance) {
            return -2;
        } else if (balance < 0) {
            return -3;
        } else {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            balance -= number;
            System.out.println("balance is:" + balance);
            System.out.println("------------------------------------------------");
            return number;
        }
    }

    /**
     * 存钱
     *
     * @param number 存钱金额
     * @return
     */
    public synchronized int saveMoney(int number, String channel) {
        System.out.println("存款开始:");
        System.out.println("存款款来自渠道:" + channel + ",账户操作前余额:" + balance);
        System.out.println("账户存款金额:" + number);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        balance += number;
        System.out.println("balance is:" + balance);
        System.out.println("------------------------------------------------");
        return number;

    }

    /**
     * 查询余额,没有关键字synchronized
     */
    public void searchBalance() {
        System.out.println("*****************************************");
        System.out.println("查询----账户余额为:" + balance);
        System.out.println("*****************************************");

    }
}

/**
 * ATM取钱
 */
class AtmFetchMoney extends Thread {
    private Bank bank;

    public AtmFetchMoney(Bank bank) {
        this.bank = bank;
    }

    @Override
    public void run() {
        bank.fetchMoney(800, "ATM");
    }
}

/**
 * 柜台取钱
 */
class GuiTaiFetchMoney extends Thread {
    private Bank bank;

    public GuiTaiFetchMoney(Bank bank) {
        this.bank = bank;
    }

    @Override
    public void run() {
        bank.fetchMoney(800, "柜台");
    }
}

/**
 * 柜台存钱
 */
class GuitaiSaveMoney extends Thread {
    private Bank bank;

    public GuitaiSaveMoney(Bank bank) {
        this.bank = bank;
    }

    @Override
    public void run() {
        bank.saveMoney(800, "柜台");
    }
}

/**
 * ATM存钱
 */
class AtmSaveMoney extends Thread {
    private Bank bank;

    public AtmSaveMoney(Bank bank) {
        this.bank = bank;
    }

    @Override
    public void run() {
        bank.saveMoney(800, "ATM");
    }
}

首先上面代码:
1.账户初始化余额1000
2.Bank有两个方法,分别是取钱和存钱的操作,取钱和存钱的操作分别传入了金额和渠道(ATM 柜台),都使用了synchronized关键字。
3.四个多线程。ATM取钱、ATM存钱、柜台存钱、柜台取钱,对其存钱和取钱的操作。
4.增加一个查询余额searchBalance()的方法,查询余额,没有关键字synchronized.
5. 模拟存钱需要等待10S,即 Thread.sleep(10000);
6.main方法中,我们多次调用查询余额方法,然后启动多个线程去操作同一个账户。分别通过ATM和柜台去存800和取款800。
如果余额依然是1000,那么说明多线程同步机制起到了实质的作用。

结果:

*****************************************
查询----账户余额为:1000
*****************************************
*****************************************
查询----账户余额为:1000
*****************************************
存款开始:
*****************************************
查询----账户余额为:1000
*****************************************
存款款来自渠道:ATM,账户操作前余额:1000
账户存款金额:800
*****************************************
查询----账户余额为:1000
*****************************************
*****************************************
查询----账户余额为:1000
*****************************************
balance is:1800
------------------------------------------------
取款开始:
取款来自渠道:柜台,账户操作前余额:1800
账户取款金额:800
balance is:1000
------------------------------------------------
取款开始:
取款来自渠道:ATM,账户操作前余额:1000
账户取款金额:800
balance is:200
------------------------------------------------
存款开始:
存款款来自渠道:柜台,账户操作前余额:200
账户存款金额:800
balance is:1000
------------------------------------------------

总结如下:

通过上面的例子可以发现,没有加synchronized关键字的方法searchBalance()不受同步机制的影响。其余的方法存款取款依次操作。不会出现竞争统一资源导致数据不对。只有当第一个线程将对象锁释放之后,后面才有执行。
上面代码可以直接copy到本地执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值