JAVA语言线程之间的通信方式实例讲解
小标 2018-09-07 来源 : 阅读 1318 评论 0

摘要:本文主要向大家介绍了JAVA语言线程之间的通信方式实例讲解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了JAVA语言线程之间的通信方式实例讲解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

1.使用Object类的方法来实现线程之间的通信

为了实现线程通信,我们可以使用Object类提供的wait()、notify()、notifyAll()三个方法。调用wait()方法会释放对该同步监视器的锁定。这三个方法必须由同步监视器对象来调用,这可分成两种情况:

对于使用synchronized修饰的同步方法,因为该类的默认实例是(this)就是同步监视器,所以可以直接调用这三使用个方法。

对于synchronized修饰的同步代码块,同步监视器是synchronized括号里的对象,所以必须使用该对象调用这三个方法。

这次我们还是拿银行账户的取钱、存款来作为本文的例子演示。

假设系统中有两条线程,这两条线程分别代表取钱者和存钱者。现在系统有一种特殊的要求,系统要求存款者和取钱者不断的实现存款和取钱动作,而且要求每当存款者将钱存入指定账户后,取钱者立即将钱取走.不允许存款者两次存钱,也不允许取钱者两次取钱.

我们通过设置一个旗标来标识账户中是否已有存款,有就为true,没有就标为false。具体代码如下:

首先我们定义一个Account类,这个类中有取钱和存钱的两个方法,由于这两个方法可能需要并发的执行取钱、存钱操作,所有将这两个方法都修改为同步方法.(使用synchronized关键字)。

public class Account { private String accountNo; private double balance; //标识账户中是否有存款的旗标 private boolean flag=false; public Account() { super(); } public Account(String accountNo, double balance) { super(); this.accountNo = accountNo; this.balance = balance; } public synchronized void draw (double drawAmount){ try { if(!flag){ this.wait(); }else {     //取钱     System.out.println(Thread.currentThread().getName()+" 取钱:"+drawAmount);     balance=balance-drawAmount;     System.out.println("余额 : "+balance);     //将标识账户是否已有存款的标志设为false     flag=false;     //唤醒其它线程     this.notifyAll(); }       } catch (Exception e) {       e.printStackTrace();   } } public synchronized void deposit(double depositAmount){ try { if(flag){ this.wait(); } else{ System.out.println(Thread.currentThread().getName()+"存钱"+depositAmount); balance=balance+depositAmount; System.out.println("账户余额为:"+balance); flag=true; //唤醒其它线程 this.notifyAll(); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); }}}

接下来创建两个线程类,分别为取钱和存钱线程!

取钱线程类:

public class DrawThread implements Runnable { private Account account; private double drawAmount; public DrawThread(Account account, double drawAmount) { super(); this.account = account; this.drawAmount = drawAmount; } public void run() { for(int i=0;i<100;i++){ account.draw(drawAmount); } }}

存钱线程类:


public class depositThread implements Runnable{private Account account;private double depositAmount; public depositThread(Account account, double depositAmount) { super(); this.account = account; this.depositAmount = depositAmount; } public void run() { for(int i=0;i<100;i++){ account.deposit(depositAmount); } }}

最后我们测试一下这个取钱和存钱的操作!
 


public  class TestDraw { public static void main(String[] args) { //创建一个账户 Account account=new Account(); new Thread(new DrawThread(account, 800),"取钱者").start(); new Thread(new depositThread(account, 800),"存款者甲").start(); new Thread(new depositThread(account, 800),"存款者乙").start(); new Thread(new depositThread(account, 800),"存款者丙").start(); }}

大致的输出结果:


 

存款者甲存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者丙存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者甲存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者丙存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者甲存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者丙存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者甲存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者丙存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0存款者甲存钱800.0账户余额为:800.0取钱者 取钱:800.0余额 : 0.0

由上述结果我们可以看到,存款者线程和取钱者线程交替执行的情形。至此简单的线程通信问题已经模拟完毕!

2.使用java.util.concurrent.locks下的Condition类来实现线程间的通信

如何程序不使用synchronized关键字来保持同步,而是直接适用Lock对像来保持同步,则系统中不存在隐式的同步监视器对象,也就不能使用wait()、notify()、notifyAll()来协调线程的运行.

当使用LOCK对象保持同步时,JAVA为我们提供了Condition类来协调线程的运行。关于Condition类,JDK文档里进行了详细的解释.,再次就不啰嗦了。

我们就拿Account类进行稍微的修改 一下吧!

import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Account { //显示定义Lock对象 private final Lock lock=new ReentrantLock(); //获得指定Lock对象对应的条件变量private final  Condition con=lock.newCondition(); private String accountNo; private double balance; //标识账户中是否有存款的旗标 private boolean flag=false; public Account() { super(); } public Account(String accountNo, double balance) { super(); this.accountNo = accountNo; this.balance = balance; } public void draw (double drawAmount){ //加锁 lock.lock(); try { if(!flag){//  this.wait(); con.await(); }else {     //取钱     System.out.println(Thread.currentThread().getName()+" 取钱:"+drawAmount);     balance=balance-drawAmount;     System.out.println("余额 : "+balance);     //将标识账户是否已有存款的标志设为false     flag=false;     //唤醒其它线程//     this.notifyAll();       con.signalAll(); }       } catch (Exception e) {       e.printStackTrace();   }       finally{       lock.unlock();       } } public void deposit(double depositAmount){ //加锁 lock.lock(); try { if(flag){// this.wait(); con.await(); } else{ System.out.println(Thread.currentThread().getName()+"存钱"+depositAmount); balance=balance+depositAmount; System.out.println("账户余额为:"+balance); flag=true; //唤醒其它线程//  this.notifyAll(); con.signalAll(); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); }finally{ lock.unlock(); }}}


输出结果和上面是一样的! 只不过这里 显示的使用Lock对像来充当同步监视器,使用Condition对象来暂停指定线程,唤醒指定线程!

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!


本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved