当线程在程序中运行时,线程的调度具有一定的透明性,程序通常无法准确控制线程的轮换执行,Java提供了一些机制来保证线程协调运行。

1、传统的线程通信借助Object类提供的wait()、notify()和notifyAll()三个方法,这三个方法必须由同步监视器对象来调用。
a、wait():导致当前线程等待,直到其他线程调用该同步监视器的notify()方法或notifyAll()方法来唤醒该线程;
b、notify():唤醒在此同步监视器上等待的单个线程;
c、notifyAll():唤醒在此同步监视器上等待的所有线程;

2、模拟情景:系统中有两个线程,分别代表存款者和取款者。系统要求存款者和取款者不断重复存款和取款的动作,而且要求每当存款者将钱存入指定账户后,取款者就立即取出该笔钱。不允许存款者连续两次存钱,也不允许取钱者连续两次取钱。

  1 /**
  2  * @Title: Account3.java
  3  * @Package
  4  * @author 任伟
  5  * @date 2014-12-8 下午6:50:34
  6  * @version V1.0
  7  */
  8
  9 /**
 10  * @ClassName: Account3
 11  * @Description: 线程安全Account类,提供存钱和取钱的操作
 12  * @author 任伟
 13  * @date 2014-12-8 下午6:50:34
 14  */
 15 public class Account3 {
 16     private String accountNo; // 账户编号
 17     private double balance; // 账户余额
 18     private boolean flag = false; // 表示账户中是否已有存款的骑标
 19
 20     public String getAccountNo() {
 21         return accountNo;
 22     }
 23
 24     public void setAccountNo(String accountNo) {
 25         this.accountNo = accountNo;
 26     }
 27
 28     public double getBalance() {
 29         return balance;
 30     }
 31
 32     public Account3() {
 33         super();
 34     }
 35
 36     public Account3(String accountNo, double balance) {
 37         super();
 38         this.accountNo = accountNo;
 39         this.balance = balance;
 40     }
 41
 42     public boolean equals(Object anObject) {
 43         if (this == anObject)
 44             return true;
 45         if (anObject != null && anObject.getClass() == Account.class) {
 46             Account target = (Account) anObject;
 47             return target.getAccountNo().equals(accountNo);
 48         }
 49         return false;
 50     }
 51
 52     public int hashCode() {
 53         return accountNo.hashCode();
 54     }
 55
 56     // 取钱操作
 57     public synchronized void draw(double drawAmount) {
 58         try {
 59             if (!flag) {//如果flag为假,表明账户中还没有人存钱进去,取钱方法阻塞
 60                 wait();
 61             } else {//否则就进行取钱操作
 62                 if (balance >= drawAmount) {
 63                     System.out.println(Thread.currentThread().getName()
 64                             + "取钱成功,吐出钞票:" + drawAmount);
 65                     try {
 66                         Thread.sleep(1);
 67                     } catch (InterruptedException e) {
 68                         e.printStackTrace();
 69                     }
 70                     balance -= drawAmount;
 71                     System.out.println("余额为:" + balance);
 72                 } else {
 73                     System.out.println(Thread.currentThread().getName()
 74                             + "取钱失败!余额不足!");
 75                 }
 76                 //将账户是否已有存款的旗标设为false
 77                 flag = false;
 78                 //唤醒其他进程
 79                 notifyAll();
 80             }
 81         } catch (Exception e) {
 82             e.printStackTrace();
 83         }
 84     }
 85
 86     //存钱操作
 87     public synchronized void deposit(double depositAmount){
 88         try{
 89             if(flag){//如果flag为真,表明账户中已有人存钱进去,存钱方法阻塞
 90                 wait();
 91             }else{
 92                 //执行存款操作
 93                 System.out.println(Thread.currentThread().getName()+" 存款:" +depositAmount);
 94                 balance += depositAmount;
 95                 System.out.println("账户余额为:" + balance);
 96                 //将账户是否已有存款的旗标设为true
 97                 flag=true;
 98                 notifyAll();
 99
100             }
101         }catch (Exception e) {
102             e.printStackTrace();
103         }
104     }
105 }

Account3

 1 /**
 2  * @Title: DrawDepositTest3.java
 3  * @Package
 4  * @author 任伟
 5  * @date 2014-12-9 下午2:09:38
 6  * @version V1.0
 7  */
 8
 9 /**
10  * @ClassName: DrawDepositTest3
11  * @Description: 测试存款和取款线程
12  * @author 任伟
13  * @date 2014-12-9 下午2:09:38
14  */
15 public class DrawDepositTest3 {
16     public static void main(String[] args) {
17         Account3 acct = new Account3("1234567", 0);
18         new DrawThread3("取钱者", acct, 800).start();
19         new DepositThread3("存钱者甲", acct, 800).start();
20         new DepositThread3("存钱者乙", acct, 800).start();
21         new DepositThread3("存钱者丙", acct, 800).start();
22     }
23 }
24
25 //取款线程
26 class DrawThread3 extends Thread{
27     private Account3 account;    //模拟用户账户
28     private double drawAmount;  //取钱数
29
30     public DrawThread3(String name, Account3 account, double drawAmount) {
31         super(name);
32         this.account = account;
33         this.drawAmount = drawAmount;
34     }
35
36     //重复100次执行取钱操作
37     public void run(){
38         for(int i=0; i<100; i++){
39             account.draw(drawAmount);
40         }
41     }
42 }
43
44 //春款线程
45 class DepositThread3 extends Thread{
46     private Account3 account;    //模拟用户账户
47     private double depositAmount;  //存钱数
48
49     public DepositThread3(String name, Account3 account, double depositAmount) {
50         super(name);
51         this.account = account;
52         this.depositAmount = depositAmount;
53     }
54
55     //重复100次执行存钱操作
56     public void run(){
57         for(int i=0; i<100; i++){
58             account.deposit(depositAmount);
59         }
60     }
61
62
63 }

DrawDepositTest3

Result


如图所示的阻塞并不是死锁,取钱者线程已经执行结束,而存款者线程只是在等待其他线程来取钱而已,并不是等待其他线程释放同步监视器。

转载于:https://www.cnblogs.com/renwei/p/4153207.html

多线程总结五:线程通信(一)相关推荐

  1. C++多线程:Linux 线程通信,唤醒,互斥锁(未完待续)

    c++ multi thread message sending and notify 线程通信常用的方法有共享内存和消息传递,推荐使用消息传递. 最常用的就是管道了,可以使用匿名管道或者命名管道. ...

  2. 深入浅出Win32多线程程序设计之线程通信

    简介 线程之间通信的两个基本问题是互斥和同步. 线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒. 线程互斥是 ...

  3. C# 多线程同步和线程通信

    多线程通信 1. 当线程之间有先后的依赖关系时,属于线程之间的通信问题.也就是后一个线程要等待别的一个或多个线程全部完成,才能开始下一步的工作.可以使用: WaitHandle Class WaitH ...

  4. 多线程 4——线程通信、线程池、定时器

    多线程 一.线程通信 1.等待集 2.wait()方法 3.notify() / notifyAll()方法 4.等待队列/同步队列 5.生产者消费者模型 二.线程池 1.jdk中的线程池 2.自己实 ...

  5. Python3进阶--Socket编程、多线程(创建方式、线程通信、线程锁、线程池)

    第一章 变量.常用循环体.代码结构.代码练习 第二章 列表.元组等数据结构.字符串驻留机制及字符串格式化操作 第三章 函数.面向对象.文件操作.深浅拷贝.模块.异常及捕获 第四章 项目打包.类和对象高 ...

  6. Java:多线程(同步死锁、锁原子变量、线程通信、线程池)

    5,同步和死锁 5.1,线程同步 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象: 修饰一个方法,被修饰的方法称为同步方法,其作用 ...

  7. 多线程——线程实现、线程状态、线程同步、线程通信、线程池

    多线程 一.线程 1.普通方法调用和多线程 2.程序.进行.线程 二.线程创建 1.继承Thread类 2.实现Runable接口 3.实现Callable接口 4.静态代理模式 5.Lamda表达式 ...

  8. java 多线程编程(包括创建线程的三种方式、线程的生命周期、线程的调度策略、线程同步、线程通信、线程池、死锁等)

    1 多线程的基础知识 1.1 单核CPU和多核CPU 单核CPU,其实是一种假的多线程,因为在一个时间单元内,也只能执行一个线程的任务.微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那 ...

  9. 多线程(三)线程通信

    线程中断.线程让步.线程睡眠.线程合并的使用推荐翻阅这篇博客:http://blog.csdn.net/ghsau/article/details/17560467 本文主要补充wait(),noti ...

最新文章

  1. 老板:kill -9的原理都不知道就敢到线上执行,明天不用来了
  2. Android 使用Jsoup解析Html
  3. UA MATH636 信息论2 数据压缩
  4. ATG中的定时Job处理
  5. linux笔记之 raid
  6. 技术分享 | 混合云模式下SaaS端前端最佳实践
  7. C语言中#、##宏定义的用法
  8. Flash在浏览器里调试获取trace
  9. cv mat保存图片_EmguCV创建/保存图片
  10. HP LaserJet P1007 装不到驱动
  11. linux ip被占用顶掉,记一次 Linux服务器被***后的排查思路
  12. 对Win10和Linux双系统进行备份
  13. Windows下硬盘存储情况可视化工具--WinDirStat
  14. Qt6 tesseract-ocr 截图识字
  15. python:图片显示
  16. 初创公司如何布局零信任网络安全?
  17. 两点之间的最短距离是?
  18. 杜君立:紧箍咒与纸枷锁
  19. 计算机CQ,[计算机软件及应用]CQ使用简介.ppt
  20. 《网络空间测绘技术与实践》正式发售,让网络空间作战“有图可依”

热门文章

  1. Apache Mahout中推荐算法Slope one源码分析
  2. 交换机端口隔离技术应用
  3. 会话技术CookieSession
  4. 折线分割平面(hdoj 2050,动态规划递推)
  5. SFB 项目经验-18-三台前端服务器同时停止两台后-前端服务启不来
  6. Spring Security源码分析十三:Spring Security 基于表达式的权限控制
  7. 我的第一个python web开发框架(1)——前言
  8. SQL 解决从分组数据中总是挑选第一条数据的问题
  9. JAVA的异常(四):finally关键字
  10. js中event,event.srcElement,event.target在IE和firefox下的兼容性