Java基础复习:线程同步练习

题目:模拟银行取款,使用三种线程同步方法实现取款的安全。编写如下类,并进行取款测试:

账户类:Account,含余额字段balance

取款类:DrawMoney,在指定帐户中进行取款操作

编写线程体:实现取款操作的安全

 

方法1:同步代码块

/**
 * 银行帐户
 */
class Account {
	/**
	 * 余额
	 */
	private double balance;
	/**
	 * 构造方法
	 * @param balance
	 */
	Account(double balance) {
		super();
		this.balance = balance;
	}
	
	//getter . setter
	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}
	
}

class ATM implements Runnable{
	/**
	 * 需要取的金额
	 */
	private double drawMoney;
	String str = new String("");//做同步代码块的监听对象
	/**
	 * 帐户
	 */
	private Account a;
	
	ATM(double drawMoney, Account a) {
		super();
		this.drawMoney = drawMoney;
		this.a = a;
	}

	public void run() {
		synchronized (str) {
			if(a.getBalance()>=drawMoney){
				System.out.println(Thread.currentThread().getName()+"吐出了"+drawMoney+"元");
				a.setBalance(a.getBalance()-drawMoney);//修改余额
			}else
			{
				System.out.println("Your account don't have enough money!");
			}
		}
	}
	
}

public class DrawMoneyDemo {
	public static void main(String[] args) {
		Account a = new Account(1000);
		ATM atm = new ATM(800,a);//从a帐户中取800元
		//假设有两个线程进行同时操作
		new Thread(atm, "A").start();
		new Thread(atm, "B").start();
	}
}

执行结果为:

B吐出了800.0元
Your account don't have enough money!

 

我们将具有原子性的代码放入 synchronized 代码块中,形成同步代码块。这样,在同一时刻只能有一个线程进入代码块执行该段代码。
格式为:

synchronized(object){

//代码块

}

 

方法2:同步方法

在帐户类中定义一个同步方法实现取款操作,这样线程执行时,只能互斥的调用该方法

/**
 * 银行帐户
 */
class Account {
	/**
	 * 余额
	 */
	private double balance;

	/**
	 * 构造方法
	 * 
	 * @param balance
	 */
	Account(double balance) {
		super();
		this.balance = balance;
	}

	// getter . setter
	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

	/**
	 * 使用同步方法的方式进行取款
	 * @param drawMoney
	 *            取款金额
	 */
	public synchronized void draw(double drawMoney) {

		if (this.getBalance() >= drawMoney) {
			System.out.println(Thread.currentThread().getName() + "吐出了"
					+ drawMoney + "元");
			this.setBalance(this.getBalance() - drawMoney);// 修改余额
		} else {
			System.out.println("Your account don't have enough money!");
		}
	}

}

class ATM implements Runnable {
	/**
	 * 需要取的金额
	 */
	private double drawMoney;
	/**
	 * 帐户
	 */
	private Account a;

	ATM(double drawMoney, Account a) {
		super();
		this.drawMoney = drawMoney;
		this.a = a;
	}

	public void run() {
		a.draw(drawMoney);
	}

}

public class DrawMoneyDemo {
	public static void main(String[] args) {
		Account a = new Account(1000);
		ATM atm = new ATM(800, a);// 从a帐户中取800元
		// 假设有两个线程进行同时操作
		new Thread(atm, "A").start();
		new Thread(atm, "B").start();
	}
}

执行结果为:

A吐出了800.0元
Your account don't have enough money!

 

 

方法3:利用Java5的同步锁机制实现线程同步

import java.util.concurrent.locks.ReentrantLock;

/**
 * 银行帐户
 */
class Account {
	/**
	 * 余额
	 */
	private double balance;
	// 定义可重入锁
	private final ReentrantLock lock = new ReentrantLock();

	/**
	 * 构造方法
	 * 
	 * @param balance
	 */
	Account(double balance) {
		super();
		this.balance = balance;
	}

	// getter . setter
	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

	/**
	 * 使用可重入锁的方式进行取款
	 * 
	 * @param drawMoney
	 *            取款金额
	 */
	public void draw(double drawMoney) {
		lock.lock();// 加锁
		try {
			if (this.getBalance() >= drawMoney) {
				System.out.println(Thread.currentThread().getName() + "吐出了"
						+ drawMoney + "元");
				this.setBalance(this.getBalance() - drawMoney);// 修改余额
			} else {
				System.out.println("Your account don't have enough money!");
			}
		} finally {
			lock.unlock();// 释放锁
		}
	}

}

class ATM implements Runnable {
	/**
	 * 需要取的金额
	 */
	private double drawMoney;
	/**
	 * 帐户
	 */
	private Account a;

	ATM(double drawMoney, Account a) {
		super();
		this.drawMoney = drawMoney;
		this.a = a;
	}

	public void run() {
		a.draw(drawMoney);
	}

}

public class DrawMoneyDemo {
	public static void main(String[] args) {
		Account a = new Account(1000);
		ATM atm = new ATM(800, a);// 从a帐户中取800元
		// 假设有两个线程进行同时操作
		new Thread(atm, "A").start();
		new Thread(atm, "B").start();
	}
}

执行结果为:

A吐出了800.0元
Your account don't have enough money!

 

对于可重入锁,其格式为:

			public class X 
			{
				private final ReentrantLock lock = new ReentrantLock();
				//定义需要保证线程安全的方法
				public void  m(){
					//加锁
					lock.lock();
					try{
						//... method body
					}finally{
						//在finally释放锁
						lock.unlock();
					}
				}
			}

使用ReentrantLock可重入锁对象可以显示的加锁和解锁,其具有与使用synchronized方法和语句所访问的隐式监听器锁相同的一些基本行为和语义,但功能更强大。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值