打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Java:多线程,使用同步锁(Lock)时利用Condition类实现线程间通信

如果程序不使用synchronized关键字来保证同步,而是直接使用Lock对象来保证同步,则系统中不存在隐式的同步监视器,也就不能用wait()、notify()、notifyAll()方法进行线程通信了。当使用Lock对象来保证同步时,Java提供了Condition类来协调线程间的通信。

本示范简单模拟银行帐户的存取款活动,帐户余额大于等于取款金额时允许取款;帐户余额小于1000时允许存款(这与真实业务逻辑不符合,只是技术上需要才如此做的,否则存款一下子全存完就不好玩了)。

1. 实体Account类

package com.clzhang.sample.thread;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class Account {    // 锁对象    private final Lock lock = new ReentrantLock();    // Condition对象    private final Condition condDeposit = lock.newCondition();    private final Condition condWithdraw = lock.newCondition();    // 为避免double类型计算的误差,balance类型设计为int的    private int balance;        public Account(int balance) {        this.balance = balance;    }    public void withdraw(int drawAmount) {        // 加锁        lock.lock();        try {            // 如果帐户余额不足,则取钱方法阻塞            while (balance < drawAmount)                condWithdraw.await();            // 执行取钱            balance -= drawAmount;            System.out.println(Thread.currentThread().getName() + " 取钱:" + drawAmount + "账户余额为:"                    + balance);            // 唤醒存款线程            condDeposit.signal();        } catch (InterruptedException ex) {            ex.printStackTrace();        } finally {            lock.unlock();        }    }    // 按照目前设计,帐户余额大于1000后不让存款,必须先取款后才能再存。    // 这与真实业务逻辑不符合,只是技术上需要才如此做的,否则存款一下子全存完就不好玩了。    public void deposit(int depositAmount) {        lock.lock();        try {            // 如果帐户余额大于1000,存钱方法阻塞            while (balance > 1000)                condDeposit.await();            // 执行存款            balance += depositAmount;            System.out.println(Thread.currentThread().getName() + " 存款:" + depositAmount + "账户余额为:"                    + balance);            // 唤醒取款线程            condWithdraw.signal();        } catch (InterruptedException ex) {            ex.printStackTrace();        } finally {            lock.unlock();        }    }}

2. 调用类(DepositDrawTest类)

package com.clzhang.sample.thread;class DrawThread extends Thread {    // 模拟用户账户    private Account account;    // 每次取钱数    private int drawAmount;    public DrawThread(String name, Account account, int drawAmount) {        super(name);        this.account = account;        this.drawAmount = drawAmount;    }    @Override    public void run() {        for (int i = 0; i < 3; i++) {            account.withdraw(drawAmount);            try {                Thread.sleep(100);            } catch (InterruptedException e) {            }        }    }}class DepositThread extends Thread {    // 模拟用户账户    private Account account;    // 每次存钱数    private int depositAmount;    public DepositThread(String name, Account account, int depositAmount) {        super(name);        this.account = account;        this.depositAmount = depositAmount;    }    @Override    public void run() {        for (int i = 0; i < 3; i++) {            account.deposit(depositAmount);            try {                Thread.sleep(100);            } catch (InterruptedException e) {            }        }    }}public class DepositDrawTest {    public static void main(String[] args) {        // 创建一个账户,初始帐户余额为0        Account acct = new Account(0);        // 注意下面的取款与存款的balance参数值需要匹配,        // 否则可能造成存款过多而不让存,然后又没有人取款导致程序无法正常终止的问题。        new DrawThread("取钱者1", acct, 400).start();        new DrawThread("取钱者2", acct, 600).start();        new DepositThread("存款者甲", acct, 600).start();        new DepositThread("存款者乙", acct, 200).start();        new DepositThread("存款者丙", acct, 400).start();    }}

输出:

存款者甲 存款:600账户余额为:600
存款者乙 存款:200账户余额为:800
存款者丙 存款:400账户余额为:1200
取钱者1 取钱:400账户余额为:800
取钱者2 取钱:600账户余额为:200
存款者乙 存款:200账户余额为:400
存款者甲 存款:600账户余额为:1000
取钱者2 取钱:600账户余额为:400
存款者丙 存款:400账户余额为:800
取钱者1 取钱:400账户余额为:400
存款者甲 存款:600账户余额为:1000
存款者丙 存款:400账户余额为:1400
取钱者1 取钱:400账户余额为:1000
存款者乙 存款:200账户余额为:1200
取钱者2 取钱:600账户余额为:600

3. 总结

  1. 如果取款金额大于余额则不让取款,等存款队列继续存钱,余额足够支付时再让取款。
  2. 如果存款过多(大于1000),则存款不让存了,等取款队列把钱取走,余额降低到1000以下时,可以继续存款。
  3. 这样就允许多次连续取款(只要帐户有钱),多次连续存款(余额不能大于1000),而不是存款、取款依次调用。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
Java总结篇系列:Java多线程(三)
Java学习——114.交互线程
Java面试题全集(1.4)
Java 多线程同步的五种方法
五种Java 多线程同步的方法
JAVA并发知识点-同步
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服