您的位置:首页 > 其它

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

2017-09-09 01:31 393 查看
上一节讲了关键字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到本地执行
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息