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

来源:互联网 发布:java线程池下载多任务 编辑:程序博客网 时间:2024/05/21 11:19

上一节讲了关键字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账户取款金额:800balance is:1000------------------------------------------------取款开始:取款来自渠道:ATM,账户操作前余额:1000账户取款金额:800balance is:200------------------------------------------------存款开始:存款款来自渠道:柜台,账户操作前余额:200账户存款金额:800balance is:1000------------------------------------------------

总结如下:

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

阅读全文
0 0