本文章内容整理自:张孝祥_Java多线程与并发库高级应用视频教程。

有些时候,线程间需要传递消息,比如下面这道面试题:

  1. 子线程循环10次,然后主线程循环100次,然后又回到子线程循环50次,然后再回到主线程循环100次。以上过程一共循环50次。

通过分析可以知道,主线程和子线程是互斥的,即主线程和子线程不能同时执行。此外,主线程和子线程有固定的轮换关系,主线程执行完后,必须是子线程接着执行,然后又是主线程执行。

要达到这种效果,光是线程互斥是不够的。因为有可能主线程执行完之后,cpu又将执行的权利分配给主线程,这样主线程又会执行一遍。要让两个线程交替执行,就需要这两个线程间可以通信。主线程执行完了,就通知子线程执行。子线程执行完了,再通知主线程执行。如此往复。

像这种线程间协作的情况,就叫线程同步。

下面直接贴出代码

  1. package com.sky.thread;
  2.  
  3. public class Test4 {
  4. private boolean mainOrSub = true;//线程间通信的变量
  5. public static void main(String[] args) {
  6. final Test4 t4 = new Test4();
  7. new Thread(new Runnable() {
  8.  
  9. @Override
  10. public void run() {
  11. //执行50次主线程
  12. for (int i = 0; i < 50; i++) {
  13. try {
  14. t4.mainThread();
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. }
  20. }).start();
  21. new Thread(new Runnable() {
  22.  
  23. @Override
  24. public void run() {
  25. //执行50次子线程
  26. for (int i = 0; i < 50; i++) {
  27. try {
  28. t4.subThread();
  29. } catch (InterruptedException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33.  
  34. }
  35. }).start();
  36. }
  37.  
  38. //主线程执行的方法
  39. public synchronized void mainThread() throws InterruptedException {
  40. //判断是否轮到自己执行
  41. //此处用while代替if,可以提高程序的健壮性。
  42. //线程有时会自己醒来,如果用if,当线程自己醒来后会接着执行this.wait()后面的代码,这样是不对的。
  43. //而使用while,线程自己醒来后,根据while的规则,会再判断一次mainOrSub的值。
  44. if (mainOrSub) {
  45. //如果mainOrSub是true,表示不该自己执行。于是把线程挂起。
  46. this.wait();
  47. }
  48. for (int i = 0; i < 100; i++) {
  49. System.out.println("main-"+Thread.currentThread().getName() + ":" + i);
  50. }
  51. //执行完毕后更改mainOrSub的状态,并唤醒其他线程
  52. mainOrSub = true;
  53. this.notify();
  54. }
  55.  
  56. //子线程执行的方法
  57. public synchronized void subThread() throws InterruptedException {
  58. //判断是否轮到自己执行
  59. while (!mainOrSub) {
  60. //如果mainOrSub是false,表示不该自己执行。于是把线程挂起。
  61. this.wait();
  62. }
  63. for (int i = 0; i < 10; i++) {
  64. System.out.println("sub-"+Thread.currentThread().getName() + ":" + i);
  65. }
  66. //执行完毕后更改mainOrSub的状态,并唤醒其他线程
  67. mainOrSub = false;
  68. this.notify();
  69. }
  70. }

在上面的代码中,创建了一个变量mainOrSub用于线程间通信。通过mainOrSub的值来控制线程的交替执行。

可见,使用多个线程都可以访问到的变量,就可以实现线程间通信。

还有一点值得注意,在判断mainOrSub的值时,用while代替了if,这样可以提高程序的健壮性。因为使用wait()挂起的线程有时会自己醒来。如果用if,当线程自己醒来后会接着执行this.wait()后面的代码,而此时并不该它执行。如果用while,线程自己醒来后,根据while的规则,会再判断一次mainOrSub的值,这样就可以保证线程完全依照mainOrSub的值来决定要不要执行。

经验:要用到共同数据(包括同步锁)的若干个方法应该归在同一个类身上,这种设计体现了高内聚和程序的健壮性。

java多线程与线程并发三:线程同步通信的更多相关文章

  1. Java多线程基础:进程和线程之由来

    转载: Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够 ...

  2. Java多线程学习(八)线程池与Executor 框架

    目录 历史优质文章推荐: 目录: 一 使用线程池的好处 二 Executor 框架 2.1 简介 2.2 Executor 框架结构(主要由三大部分组成) 2.3 Executor 框架的使用示意图 ...

  3. Java多线程-两种常用的线程计数器CountDownLatch和循环屏障CyclicBarrier

    Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-从一个错误的双重校验锁 ...

  4. 1、Java多线程基础:进程和线程之由来

    Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...

  5. Java 多线程基础(四)线程安全

    Java 多线程基础(四)线程安全 在多线程环境下,如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线 ...

  6. Java 多线程基础(五)线程同步

    Java 多线程基础(五)线程同步 当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题. 要解决上述多线程并发访问一个资源的安全性问题,Java中提供了同步机制 ...

  7. Java 多线程基础(十一)线程优先级和守护线程

    Java 多线程基础(十一)线程优先级和守护线程 一.线程优先级 Java 提供了一个线程调度器来监控程序启动后进去就绪状态的所有线程.线程调度器通过线程的优先级来决定调度哪些线程执行.一般来说,Ja ...

  8. Java 多线程基础(六)线程等待与唤醒

    Java 多线程基础(六)线程等待与唤醒 遇到这样一个场景,当某线程里面的逻辑需要等待异步处理结果返回后才能继续执行.或者说想要把一个异步的操作封装成一个同步的过程.这里就用到了线程等待唤醒机制. 一 ...

  9. Java 多线程基础(七)线程休眠 sleep

    Java 多线程基础(七)线程休眠 sleep 一.线程休眠 sleep sleep() 方法定义在Thread.java中,是 static 修饰的静态方法.sleep() 的作用是让当前线程休眠, ...

  10. Java 多线程基础(八)线程让步

    Java 多线程基础(八)线程让步 yield 一.yield 介绍 yield()的作用是让步.它能让当前线程由“运行状态”进入到“就绪状态”,从而让其它具有相同优先级的等待线程获取执行权:但是,并 ...

随机推荐

  1. django渲染高阶

    08.16自我总结 django渲染高阶 一.利用母版渲染 1.创建母版文件 如:stamper.html <!DOCTYPE html> <html lang="en&q ...

  2. 代码审计-EasyCMS

    cms来源AWD线下攻防平台题目.  链接:https://pan.baidu.com/s/1eUkyRspQmsv-0fIBby8ZlQ  提取码:tywa 失效可以联系我   0x01 文件上传漏 ...

  3. JavaScript回调函数和递归函数

    一.回调函数--通过函数的指针来调用函数 把一个函数的指针作为另一个函数的参数,当调用这个参数的时候,这个函数就叫做回调函数 在链式运动上会用到回调函数,之后运动会见到 A.通过指针来调用函数 B.通 ...

  4. iguana::json/xml 序列化框架

    环境:win10  vs2017  c++17  boost 1.下载源码:https://github.com/qicosmos/iguana 2.创建工程,包含源码目录.boost库目录:boos ...

  5. Spring Cloud Alibaba (nacos 注册中心搭建)

    [nacos下载地址](https://github.com/alibaba/nacos/releases) ### 什么是 Nacos? - nacos主要起到俩个作用一个是注册中心,另外一个是配置 ...

  6. 浅谈线段树 Segment Tree

    众所周知,线段树是algo中很重要的一项! 一.简介 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在 ...

  7. Mongoose-modified-at 时间自动记录插件介绍

    Mongoose-modified-at 是一款自动更新字段变化时间并记录到数据库中的 Mongoose 插件,类似 Mongoose 自带的 timestamps 功能. 使用场景 让我们考虑一个场 ...

  8. 让button的文字换行和左对齐

    btn.titleLabel.numberOfLines = 0;   btn.contentHorizontalAlignment = UIControlContentHorizontalAlign ...

  9. Java自动化测试框架-04 - 来给你的测试报告化个妆整个形 - (上)(详细教程)

    简介 前边通过宏哥的讲解和分享想必小伙伴们和童鞋们都已经见过testng框架生成的测试报告,是不是它的样子和长相实在是不敢让大家伙恭维.那么今天宏哥就当一回美容师,由宏哥来给它美美容:当一回外科医生, ...

  10. hexo博客yili主题个性化自定义教程(1) ——借鉴中学习,初认yili主题

    文章转载于:hexo博客yili主题个性化自定义教程(1) --借鉴中学习,初认yili主题 这个博客跌跌撞撞也弄了好多天了,由于Next主题不知道什么情况,被我玩坏了.所以换了一个主题. 大名鼎鼎的 ...