Java多线程协调控制之wait&notifyAll

最近在复习Java基础,看到多线程这块顺便写写多线程的协调控制程序。


需求:假设系统中有两个线程分别代表取款者和存款者,现在系统的要求是存款者和取款者不断的重复存、取款操作,

并且要求每当有存款者将钱存入指定账户中时,取款者就立即取出这笔钱,即不允许存款者连续两次存钱,也不允许

取款者两次取钱。


下面代码实现:

1.首先是账户Account类;

package com.xjtu.cruise.soft.thread;

public class Account {

	/**
	 * @author Cruise
	 * @param args
	 */
	private String accountNo;
	//标识账户是否还有存款的
	private boolean flag = false;
	private double balance;

	public Account(){}
	public Account(String accountNo, double balance) {
		this.accountNo = accountNo;
		this.balance = balance;
	}

	public double getBalance(){
		return balance;
	}
	public synchronized void draw(double drawAmount) {
		try {
			if (!flag) {  //如果账户没钱
				wait();  //阻塞当前的方法,并释放同步锁(这里就是this,也就是调用此方法的对象)
			} else {
				System.out.println("线程:" + Thread.currentThread().getName()
						+ "取款" + drawAmount);
				balance -= drawAmount;
				System.out.println("账户余额:" + balance);
				flag = false;
				notifyAll();  //唤醒等待此同步锁的所有线程
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public synchronized void deposit(double depositAmount) {

		try{
			if(flag){ //如果账户有存入的钱
				wait();
			}else{
				System.out.println("线程:"+ Thread.currentThread().getName()+"存款"+depositAmount);
				balance += depositAmount;
				System.out.println("账户余额:" + balance);
				flag = true;
				notifyAll();
			}
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}

}


 2.接下来是存取款线程类(DrawThread,DepositThread) 

package com.xjtu.cruise.soft.thread;

public class DepositThread extends Thread {

	private Account account;
	private double depositAmount;

	public DepositThread(String name, Account account, double depositAmount) {
		super(name);
		this.account = account;
		this.depositAmount = depositAmount;
	}
	
	public void run(){
		for(int i=0; i<100; i++){
//			System.out.println("线程:" + Thread.currentThread().getName()+"执行存款操作。");
			account.deposit(depositAmount);
		}
	}
}

package com.xjtu.cruise.soft.thread;

public class DrawThread extends Thread {
/**
     * @author Cruise
     * @param args
     */
	private Account account;
	private double drawAmount;

	public DrawThread(String name, Account account, double drawAmount) {
		super(name);
		this.account = account;
		this.drawAmount = drawAmount;
	}
	
	public void run(){
		for(int i=0; i<100; i++){
//			System.out.println("线程:" + Thread.currentThread().getName()+"执行取钱操作。");
			account.draw(drawAmount);
		}
	}
}

3.奉上测试类TestDraw

package com.xjtu.cruise.soft.thread;

public class TestDraw {

	/**
	 * @author Cruise
	 * @param args
	 */
	public static void main(String[] args) {
		Account account = new Account("123", 0);
		new DrawThread("取钱者", account, 800).start();
		new DepositThread("存款者甲",account, 800).start();
		new DepositThread("存款者乙",account, 800).start();

	}

}

OK, 一个使用wait和notifyAll控制线程协调的Demo完成,运行结果如下:


下面再使用条件变量的方式来协调线程的同步,具体来说就是使用Lock对象来保证同步,而不是用Synchronized关键字。

通过Lock实例调用其newCondition()方法得到对应的Condition对象,接着使用此Condition实例的方法来保证线程的协

调。这里用到了Condition的await和signalAll方法。

将上面的Account类修改如下,其他的线程类不变。

package com.xjtu.cruise.soft.thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Account {

	/**
	 * @author Cruise
	 * @param args
	 */
	private final Lock lock = new ReentrantLock();//定义Lock对象
	private final Condition cond = lock.newCondition();//获取Lock对象对应的条件变量
	private String accountNo;
	//标识账户是否还有存款的
	private boolean flag = false;
	private double balance;

	public Account(){}
	public Account(String accountNo, double balance) {
		this.accountNo = accountNo;
		this.balance = balance;
	}

	public double getBalance(){
		return balance;
	}
	public void draw(double drawAmount) {
		lock.lock();//加锁
		try {
			if (!flag) {  //如果账户没钱
				cond.await();  
			} else {
				System.out.println("线程:" + Thread.currentThread().getName()
						+ "取款" + drawAmount);
				balance -= drawAmount;
				System.out.println("账户余额:" + balance);
				flag = false;
				cond.signalAll();  //唤醒该Lock对象对应的其他线程
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			lock.unlock();//使用finally块确保释放锁
		}
	}

	public void deposit(double depositAmount) {
		lock.lock();//加锁
		try{
			if(flag){ //如果账户有存入的钱
				cond.await();
			}else{
				System.out.println("线程:"+ Thread.currentThread().getName()+"存款"+depositAmount);
				balance += depositAmount;
				System.out.println("账户余额:" + balance);
				flag = true;
				cond.signalAll();//唤醒该Lock对象对应的其他线程
			}
		}catch(InterruptedException e){
			e.printStackTrace();
		}finally{//使用finally块确保释放锁
			lock.unlock();
		}
	}

}

运行上面的测试类,可以得到如下的运行结果:

从上面的两个运行结果可以发现,虽然两种方法都可以保证线程的同步和协调运行,但是线程的调度机制还是有些许的

差别,这点可以从上图的红框看出。当然底层的具体实现,因为不大了解,这里就不作具体的阐述了(废话,不了解当

然阐述不了,^_^),希望了解的同学能帮忙解答下,very thx!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值