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. 总结
- 如果取款金额大于余额则不让取款,等存款队列继续存钱,余额足够支付时再让取款。
- 如果存款过多(大于1000),则存款不让存了,等取款队列把钱取走,余额降低到1000以下时,可以继续存款。
- 这样就允许多次连续取款(只要帐户有钱),多次连续存款(余额不能大于1000),而不是存款、取款依次调用。
Java:多线程,使用同步锁(Lock)时利用Condition类实现线程间通信的更多相关文章
- 《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析
不使用等待通知机制 实现线程间通信的 疑问分析 2018年04月03日 17:15:08 ayf 阅读数:33 编辑 <java多线程编程核心技术>一书第三章开头,有如下案例: ...
- 《JAVA多线程编程核心技术》 笔记:第三章:线程间通信
一. 等待/通知机制:wait()和notify()1.1.使用的原因:1.2 具体实现:wait()和notify()1.2.1 方法wait():1.2.2 方法notify():1.2.3 wa ...
- 扯扯python的多线程的同步锁 Lock RLock Semaphore Event Condition
我想大家都知道python的gil限制,记得刚玩python那会,知道了有pypy和Cpython这样的解释器,当时听说是很猛,也就意味肯定是突破了gil的限制,最后经过多方面测试才知道,还是那德行… ...
- Windows环境下多线程编程原理与应用读书笔记(4)————线程间通信概述
<一>线程间通信方法 全局变量方式:进程中的线程共享全局变量,可以通过全局变量进行线程间通信. 参数传递法:主线程创建子线程并让子线程为其服务,因此主线程和其他线程可以通过参数传递进行通信 ...
- java并发编程(十)使用wait/notify/notifyAll实现线程间通信
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17225469 wait()方法:public final void wait() thr ...
- Java多线程编程(同步、死锁、生产消费者问题)
Java多线程编程(同步.死锁.生产消费): 关于线程同步以及死锁问题: 线程同步概念:是指若干个线程对象并行进行资源的访问时实现的资源处理保护操作: 线程死锁概念:是指两个线程都在等待对方先完成,造 ...
- java线程间通信1--简单实例
线程通信 一.线程间通信的条件 1.两个以上的线程访问同一块内存 2.线程同步,关键字 synchronized 二.线程间通信主要涉及的方法 wait(); ----> 用于阻塞进程 noti ...
- python笔记9 线程进程 threading多线程模块 GIL锁 multiprocessing多进程模块 同步锁Lock 队列queue IO模型
线程与进程 进程 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数据集则是程序在执行过程中所需要 ...
- python 多线程中的同步锁 Lock Rlock Semaphore Event Conditio
摘要:在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lo ...
随机推荐
- Django1.9 Python3.4出现Error loading MySQLdb
linux Errorloading MySQLdb module: No module named MySQLdb 这是因为目前 MySQLdb 还不支持 python3.x ,开源无人维护哈 之前 ...
- CUBRID学习笔记 47 show
cubrid的中sql查询语法show c#,net,cubrid,教程,学习,笔记欢迎转载 ,转载时请保留作者信息.本文版权归本人所有,如有任何问题,请与我联系wang2650@sohu.com . ...
- CUBRID学习笔记 41 sql语法之select
cubrid的中sql查询语法 SELECT [ ] [{TO | INTO} ][FROM ] [WHERE ][GROUP BY {col_name | expr} [ASC | DESC], . ...
- poj 2318 TOYS (二分+叉积)
http://poj.org/problem?id=2318 TOYS Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 101 ...
- iOS - AudioServicesPlay 短频音效播放
前言 extern void AudioServicesPlayAlertSound(SystemSoundID inSystemSoundID) __OSX_AVAILABLE_STARTING(_ ...
- mongoDB 类型参考表
$type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果. MongoDB 中可以使用的类型如下表所示: 参考资料:http://www.runoob.com/mongodb/mong ...
- Android GestureDetector方法详解
为了加强点击.拖动响应事件,Android提供了GestureDetector手势识别类.通过GestureDetector.OnGestureListener来获取当前被触发的操作手势(Single ...
- ip变更导致连接不到mysql的解决办法
第一步:ssh连接到服务器 第二步:连接mysql mysql -u root -psqj888 第三步:切换到mysql数据库 use mysql 第四步:查询mysql的user表 SELECT ...
- C++模板(基础)
本文转至:http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html C++模板 模板是C++支持参数化多态的工具,使用模板可以使用户为类 ...
- spring 配置触发器
原转发的博文 http://blog.csdn.net/liaq325/article/details/8269439 在Spring中配置Quartz 前面介绍过了Timer在Spring中的实现, ...