采用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;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((accountNo == null) ? 0 : accountNo.hashCode());
		long temp;
		temp = Double.doubleToLongBits(balance);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Account other = (Account) obj;
		if (accountNo == null) {
			if (other.accountNo != null)
				return false;
		} else if (!accountNo.equals(other.accountNo))
			return false;
		if (Double.doubleToLongBits(balance) != Double
				.doubleToLongBits(other.balance))
			return false;
		return true;
	}
	
}

 

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();
	}
}

 

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

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

 

 

采用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;
	}


	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((accountNo == null) ? 0 : accountNo.hashCode());
		long temp;
		temp = Double.doubleToLongBits(balance);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Account other = (Account) obj;
		if (accountNo == null) {
			if (other.accountNo != null)
				return false;
		} else if (!accountNo.equals(other.accountNo))
			return false;
		if (Double.doubleToLongBits(balance) != Double
				.doubleToLongBits(other.balance))
			return false;
		return true;
	}
	
}

 

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
取钱失败,余额不足!

 

 

你可能感兴趣的:(多线程,同步)