`

采用synchonized保证线程同步

阅读更多

关于线程安全问题有一个经典的例子就是----银行取钱问题

  1. 用户输入账号密码,系统匹配账号密码是否正确
  2. 用户输入取款金额
  3. 系统判断账号余额是否大于取款金额
  4. 如果余额大于取款金额则取款成功,反正取款失败
package com.synchronized1;
public class Account {
        //账号ID
	private String accountNo;
	//余额
	private double balance;
	public Account(String accountNo, double balance) {
		super();
		this.accountNo = accountNo;
		this.balance = balance;
	}
	public String getAccountNo() {
		return accountNo;
	}
	public void setAccountNo(String accountNo) {
		this.accountNo = accountNo;
	}
	public double getBalance() {
		return balance;
	}
	public void setBalance(double balance) {
		this.balance = balance;
	}
	
}

 

package com.synchronized1;

public class DrawMoney implements Runnable {

	private Account account;
	private double drawAmount;
	private String name;
	
	public DrawMoney(String name,Account account,double drawAmount) {
		this.name = name;
		this.account = account;
		this.drawAmount = drawAmount;
	}

	@Override
	public void run() {
		if(account.getBalance()>drawAmount){
			System.out.println(name+"取钱成功,吐出钞票:"+drawAmount);
			account.setBalance(account.getBalance()-drawAmount);
			System.out.println("余额:"+account.getBalance());
		}else{
			System.out.println("取钱失败,余额不足!");
		}
	}
}

 

package com.synchronized1;

public class DrawMain {

	public static void main(String[] args) {
		Account ac=new Account("111", 1000);
		new Thread(new DrawMoney("甲", ac, 800)).start();
		new Thread(new DrawMoney("乙", ac, 800)).start();
	}
}

 

 问题出现了:账户余额只有1000的时候取出了1600

乙取钱成功,吐出钞票:800.0
甲取钱成功,吐出钞票:800.0
余额:200.0
余额:-600.0

 

 

采用synchronized保证线程安全:

package com.synchronized2;

public class DrawMoney implements Runnable {

	private Account account;
	private double drawAmount;
	private String name;
	
	public DrawMoney(String name,Account account,double drawAmount) {
		this.name = name;
		this.account = account;
		this.drawAmount = drawAmount;
	}

	@Override
	public void run() {
		//使用account作为同步监视器,任何线程进入下面的同步代码块之前必须先
		//获得account账户的锁定
		synchronized(account){
			if(account.getBalance()>drawAmount){
				System.out.println(name+"取钱成功,吐出钞票:"+drawAmount);
				account.setBalance(account.getBalance()-drawAmount);
				System.out.println("余额:"+account.getBalance());
			}else{
				System.out.println("取钱失败,余额不足!");
			}
	  }
   }

}

 

甲取钱成功,吐出钞票:800.0
余额:200.0
取钱失败,余额不足!

 

 

更好的设计方式:

package com.synchronized3;

public class Account{
    //账号ID
	private String accountNo;
	//余额
	private double balance;
	
	public Account(String accountNo, double balance) {
		super();
		this.accountNo = accountNo;
		this.balance = balance;
	}
	
	public synchronized void draw(double drawAmount){
		if(balance>=drawAmount){
			System.out.println(Thread.currentThread().getName()+" 取钱成功,吐出钞票:"+drawAmount);
			balance-=drawAmount;
			System.out.println("余额:"+(balance-drawAmount));
		}else{
			System.out.println("取钱失败,余额不足!");
		}
	}
	public String getAccountNo() {
		return accountNo;
	}
	public void setAccountNo(String accountNo) {
		this.accountNo = accountNo;
	}
	public double getBalance() {
		return balance;
	}
}

 

package com.synchronized3;

public class DrawMoney implements Runnable {

	private Account account;
	private double drawAmount;
	
	public DrawMoney(Account account,double drawAmount) {
		this.account = account;
		this.drawAmount = drawAmount;
	}

	@Override
	public void run() {
		//同步方法的同步不监视器是this,this代表draw方法的对象(Account对象)
		account.draw(drawAmount);
	}

}

 

package com.synchronized3;
public class DrawMain {
	public static void main(String[] args) {
		Account ac=new Account("111", 1000);
		new Thread(new DrawMoney( ac, 800)).start();
		new Thread(new DrawMoney(ac, 800)).start();
	}
}

 

Thread-0 取钱成功,吐出钞票:800.0
余额:-600.0
取钱失败,余额不足!

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics