线程间的相互作用

  线程之间需要一些协调通信,来共同完成一件任务。

  Object类相关的方法:notify(),notifyAll(),wait()。会被所有的类继承,这些方法是final不能被重写。他们操控的是每个对象都会有的锁,如果不在synchronized里面调用wait,notify,notifyAll方法,运行时会报异常:要调用对象的这些方法,必须先获得这个对象的锁。

wait():

  使得当前线程必须等待,进入到等待序列,等到另外一个线程调用notify()或者notifyAll()激活

  当前线程必须拥有当前对象的monitor,就是锁。线程调用wait(),释放对锁的拥有权,等待另外的线程来通知他,这样才能重新获得锁的拥有权和恢复执行。

  要确保调用wait()方法的时候拥有锁。

  调用Object.wait()方法,会释放对象的锁。调用Thread.sleep()方法,不会释放对象的锁。

notify():

  唤醒一个等待当前对象的锁的线程,如果多个线程在等待,他们中的一个将会被选择唤醒,这种选择是随意的。

  被唤醒的锁是不能被执行的,必须要等到当前线程放弃这个对象的锁,被唤醒的线程和其他线程竞争锁。

一个线程拥有一个对象的锁有以下几种方法:

1.执行这个对象的synchronized实例方法

2.执行这个对象的synchronized语句块,这个语句块锁的是这个对象

3.对于class类的对象,执行那个类的synchronized static方法

学到线程通信就必须看看经典例子:生产/消费问题

  1. 生产者在仓库未满的时候生产,仓库满则停止生产
  2. 消费者仅仅在仓库有产品的时候才能消费,仓空则等待
  3. 消费者发现仓库没产品消费时,通知生产者等待
  4. 生产者在生产处可消费产品时,通知等待的消费者去消费

初步设计:

1.Depot是“仓库”类,仓库中记录“仓库的容量(capacity)”以及“仓库中当前产品数目(size)”。

  “仓库”类的生产方法produce()和消费方法consume()方法都是synchronized方法,进入synchronized方法体,意味着这个线程获取到了该“仓库”对象的同步锁。这也就是说,同一时间,生产者和消费者线程只能有一个能运行。通过同步锁,实现了对“仓库”的互斥访问。

produce()方法:仓库满时,生产者线程进入等待,生产完成,通过nofityAll()唤醒所有的线程,consume()方法:消费者进行消费之后,会通过nofityAll()方法通知生产者进行生产

2.Producer类:生产者类,每次会新建一个线程调用仓库的produce()方法进行生产

3.Customer类:消费者类,每次会新建一个线程调用仓库的consume()方法进行消费

4.定义若干次消费和生产,看是不是满足关系

  1. package com.template.ProduceConsume;
  2.  
  3. /**
  4. * <生产者和消费者>
  5. * <详细介绍>
  6. *
  7. * @author 姬国靖
  8. * @since 设计wiki | 需求wiki
  9. */
  10. public class test {
  11. public static void main(String[] args) {
  12. Depot mDepot = new Depot(100);
  13. Producer mPro = new Producer(mDepot);
  14. Customer mCus = new Customer(mDepot);
  15.  
  16. mPro.produce(60);
  17. mPro.produce(120);
  18. mCus.consume(90);
  19. mCus.consume(150);
  20. mPro.produce(110);
  21. }
  22. }
  23.  
  24. //仓库
  25. class Depot {
  26. private int capacity; // 仓库的容量
  27. private int size; // 仓库的实际数量
  28.  
  29. public Depot(int capacity) {
  30. this.capacity = capacity;
  31. this.size = 0;
  32. }
  33.  
  34. public synchronized void produce(int val) {
  35. try {
  36. // left 表示“想要生产的数量”(有可能生产量太多,需多此生产)
  37. int left = val;
  38. while (left > 0) {
  39. // 库存已满时,等待“消费者”消费产品。
  40. while (size >= capacity)
  41. wait();
  42. // 获取“实际生产的数量”(即库存中新增的数量)
  43. // 如果“库存”+“想要生产的数量”>“总的容量”,则“实际增量”=“总的容量”-“当前容量”。(此时填满仓库)
  44. // 否则“实际增量”=“想要生产的数量”
  45. int inc = (size+left)> capacity ? (capacity-size) : left;
  46. size += inc;
  47. left -= inc;
  48. System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d\n",
  49. Thread.currentThread().getName(), val, left, inc, size);
  50. // 通知“消费者”可以消费了。
  51. notifyAll();
  52. }
  53. } catch (InterruptedException e) {
  54. }
  55. }
  56.  
  57. public synchronized void consume(int val) {
  58. try {
  59. // left 表示“客户要消费数量”(有可能消费量太大,库存不够,需多此消费)
  60. int left = val;
  61. while (left > 0) {
  62. // 库存为0时,等待“生产者”生产产品。
  63. while (size <= 0)
  64. wait();
  65. // 获取“实际消费的数量”(即库存中实际减少的数量)
  66. // 如果“库存”<“客户要消费的数量”,则“实际消费量”=“库存”;
  67. // 否则,“实际消费量”=“客户要消费的数量”。
  68. int dec = (size<left) ? size : left;
  69. size -= dec;
  70. left -= dec;
  71. System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d\n",
  72. Thread.currentThread().getName(), val, left, dec, size);
  73. notifyAll();
  74. }
  75. } catch (InterruptedException e) {
  76. }
  77. }
  78.  
  79. public String toString() {
  80. return "capacity:"+capacity+", actual size:"+size;
  81. }
  82. }
  83.  
  84. //生产者
  85. class Producer {
  86. private Depot depot;
  87.  
  88. public Producer(Depot depot) {
  89. this.depot = depot;
  90. }
  91.  
  92. // 消费产品:新建一个线程向仓库中生产产品。
  93. public void produce(final int val) {
  94. new Thread() {
  95. public void run() {
  96. depot.produce(val);
  97. }
  98. }.start();
  99. }
  100. }
  101.  
  102. //消费者
  103. class Customer {
  104. private Depot depot;
  105.  
  106. public Customer(Depot depot) {
  107. this.depot = depot;
  108. }
  109.  
  110. // 消费产品:新建一个线程从仓库中消费产品。
  111. public void consume(final int val) {
  112. new Thread() {
  113. public void run() {
  114. depot.consume(val);
  115. }
  116. }.start();
  117. }
  118. }

分析:可以看出仓库满时停止生产,等待消费者通知,不够消费停止消费,,等待生产者通知

多线程编程-- part 4 线程间的通信的更多相关文章

  1. java多线程详解(6)-线程间的通信wait及notify方法

    Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New) ...

  2. Java 多线程(七) 线程间的通信——wait及notify方法

    线程间的相互作用 线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务. Object类中相关的方法有两个notify方法和三个wait方法: http://docs.oracle.com/ ...

  3. iOS开发多线程篇—线程间的通信

    iOS开发多线程篇—线程间的通信 一.简单说明 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传递数据给另1个线程 在1个线程中执行完特定任 ...

  4. iOS边练边学--多线程NSOperation介绍,子类实现多线程的介绍(任务和队列),队列的取消、暂停(挂起)和恢复,操作依赖与线程间的通信

    一.NSOperation NSOperation和NSOperationQueue实现多线程的具体步骤 先将需要执行的操作封装到一个NSOperation对象中 然后将NSOperation对象添加 ...

  5. Java多线程中线程间的通信

    一.使用while方式来实现线程之间的通信 package com.ietree.multithread.sync; import java.util.ArrayList; import java.u ...

  6. iOS开发多线程篇 04 —线程间的通信

    iOS开发多线程篇—线程间的通信 一.简单说明 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传递数据给另1个线程 在1个线程中执行完特定任 ...

  7. Java基础教程:多线程基础(2)——线程间的通信

    Java基础教程:多线程基础(2)——线程间的通信 使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时还会使程序员对各线程任务在处理的过程中进行有效的把控与监督. 线程间的通信 ...

  8. Java并发编程(04):线程间通信,等待/通知机制

    本文源码:GitHub·点这里 || GitEE·点这里 一.概念简介 1.线程通信 在操作系统中,线程是个独立的个体,但是在线程执行过程中,如果处理同一个业务逻辑,可能会产生资源争抢,导致并发问题, ...

  9. Java核心知识点学习----多线程并发之线程间的通信,notify,wait

    1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...

随机推荐

  1. RF框架自定义测试库开发

    静态库 方法(methods)直接映射为关键字名称.关键字接受和方法相同的参数, 通过抛异常来 报告错误, 通过往标准输出里写入来写 log, 同时可以通过return 来返回结果. 创建步骤: ▲ ...

  2. 通过ID获取元素

    网页由标签将信息组织起来,而标签的id属性值是唯一的,就像是每人有一个身份证号一样,只要通过身份证号就可以找到相对应的人.那么在网页中,我们通过id先找到标签,然后进行操作. 语法: document ...

  3. ACCESS_ONCE的作用

    如果你看过 Linux 内核中的 RCU 的实现,你应该注意到了这个叫做 ACCESS_ONCE() 宏. ACCESS_ONCE的定义如下: #define __ACCESS_ONCE(x) ({ ...

  4. LC 662. Maximum Width of Binary Tree

    Given a binary tree, write a function to get the maximum width of the given tree. The width of a tre ...

  5. GitHub:Facebook

    ylbtech-GitHub:Facebook 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部 1. https://github.com/facebook 2. ...

  6. MySQL数据表列转行

    简单例子 数据结构如下 use dataTest create table t_score ( name ) , subject ), grade ,) ) INSERT INTO `t_score` ...

  7. Django-给视图加装饰器

    给FBV加装饰器 FBV:function based view FBV本身就是一个函数,所以跟普通函数加装饰器是一样的 # 装饰函数是要在APP文件中定义,本例是在app01\templatetag ...

  8. 【科普杂谈】一文看懂大数据的技术生态圈,Hadoop,hive,spark都有了

    大数据本身是个很宽泛的概念,Hadoop生态圈(或者泛生态圈)基本上都是为了处理超过单机尺度的数据处理而诞生的.你可以把它比作一个厨房所以需要的各种工具.锅碗瓢盆,各有各的用处,互相之间又有重合.你可 ...

  9. 【DSP开发】【图像处理】Gray与YUV之间的转换关系

    标准的V4L2 API http://v4l.videotechnology.com/dwg/v4l2.pdf 在例程/home/dvevm_1_20/demos/ImageGray中,涉及到图像采集 ...

  10. Redis高级主题

    Redis高级主题   持久化 Redis 支持持久化, 其持久化数据有两种方式. 两种可以同时使用. 如果同时使用, Reids 在重启时将使用 AOF 方式来还原数据. RDB 按照一定策略定时同 ...