《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析
不使用等待通知机制 实现线程间通信的 疑问分析
2018年04月03日 17:15:08 ayf
阅读数:33 编辑
《java多线程编程核心技术》一书第三章开头,有如下案例:
线程A:
package extthread; import mylist.MyList; public class ThreadA extends Thread { private MyList list; public ThreadA(MyList list) { super(); this.list = list; } @Override public void run() { try { for (int i = 0; i < 10; i++) { list.add(); System.out.println("添加了" + (i + 1) + "个元素"); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } }
线程B:
package extthread; import mylist.MyList; public class ThreadB extends Thread { private MyList list; public ThreadB(MyList list) { super(); this.list = list; } @Override public void run() { try { while (true) { if (list.size() == 5) { System.out.println("==5了,线程b要退出了!"); throw new InterruptedException(); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
MyList.java代码:
package mylist; import java.util.ArrayList; import java.util.List; public class MyList { private List list = new ArrayList(); public void add() { list.add("高洪岩"); } public int size() { return list.size(); } }
运行类Test.java代码:
package test; import mylist.MyList; import java.util.concurrent.ThreadPoolExecutor; import extthread.ThreadA; import extthread.ThreadB; public class Test { public static void main(String[] args) { MyList service = new MyList(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); } }
程序执行,按照书中所描述,应该出现如图所示结果:B线程抛出异常,停止运行。
但是实际上本地运行结果如下,没有抛出异常:B线程还是一直在进行while循环
这让我十分困惑。就进行各种测试,我在B线程的while循环体里面,加了一句打印代码,B线程的while循环代码变为如下:
while (true) { System.out.println(list.size()); if (list.size() == 5) { System.out.println("==5了,线程b要退出了!"); throw new InterruptedException(); } }
再次执行,竟然发现能够打印出异常了,既然异常抛出,那肯定B线程停了,等A运行结束,虚拟机也停止运行了。如图:
只是添加了一句打印的代码,竟然会影响程序的执行逻辑???这是什么原因?另外,我又继续做了如下测试:
1. while (true) { 2. //System.out.println("B一直在执行"); 3. int a = 10; 4. if (list.size() == 5) { 5. System.out.println("==5了,线程b要退出了!"); 6. throw new InterruptedException(); 7. } 8. }
把上面说的那一句system.out.println改为 int a = 10;====》B线程不能抛出异常,A线程循环输出完毕,虚拟机不停。
继续,在B线程 if 分支处打断点,debug运行来看,控制台一直在运行打印输出A添加了x个元素,证明A线程在一直跑,没错。B中Size也是在变化的,可是当size等于if条件语句中的值(5)时,却没有进入if代码块里面去执行,所以抛出异常又从何谈起呢?
而且,今晚我又发现,if语句中list.size == 1时,能实现效果,如下图:
当 list.size == 其他数值时,比如原文中的 5、又比如自己尝试的6、7、4、3等,均不行。如图:
但此时,如果添加上面所说的输出语句,B线程可以抛出异常。若添加一般常量定义语句,eg: int a = 10;,B线程不能抛出异常。
综上,若想实现书中的效果(在A线程不断添加元素到list中去,B获取size抛出异常),有如下三种方式:
①B线程 while 循环 内 添加输出打印语句。(真心不懂,估计和system类底层有关,求大佬赐教)
②if判断条件 list.size 改为 == 1。 至于原因,也是迷迷糊糊的。
③既然B线程不抛出异常,说明没有执行if代码内容。联系到第二章最后的volatile。所以我尝试了第三种方式:
更改MyList.java的size方法代码,添加synchronized,锁定任意String对象,强制同步主内存与线程私有内存的list的内容,效果如下图,是可以实现目的 的。
或者改成直接锁list也是同样的道理
上面就是我所发现的分析过程,希望大佬能够不吝赐教,分析一下原因。感激不尽,谢谢。
============20190414===========
这个问题今年前一段时间,再次看到这里,我又写了一些demo小例子,进行一些验证。其实也没有什么难理解的,其实就是变量在县城之间的可见性问题。感觉书中的代码有些不严谨。。。
《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析的更多相关文章
- 【Java并发编程】:使用wait/notify/notifyAll实现线程间通信
在java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信.在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调 ...
- 二、java多线程编程核心技术之(笔记)——如何停止线程?
1.异常法 public class MyThread extends Thread { @Override public void run() { super.run(); try { for (i ...
- Java多线程编程核心技术(三)多线程通信
线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时 ...
- java多线程编程核心技术——第三章
第一节等待/通知机制 1.1不使用等待/通知机制实现线程间的通讯 1.2什么是等待/通知机制 1.3等待/通知机制的实现 1.4方法wait()锁释放与notify()锁不释放 1.5当interru ...
- java多线程编程核心技术——第三章总结
第一节等待/通知机制 1.1不使用等待/通知机制实现线程间的通讯 1.2什么是等待/通知机制 1.3等待/通知机制的实现 1.4方法wait()锁释放与notify()锁不释放 1.5当interru ...
- 《Java多线程编程核心技术》读后感(八)
不使用等待/通知机制实现线程间通信 使用sleep()结合while(true)死循环来实现多个线程间通信 package Third; import java.util.ArrayList; imp ...
- Java多线程编程核心技术
Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...
- Java多线程编程核心技术(一)Java多线程技能
1.进程和线程 一个程序就是一个进程,而一个程序中的多个任务则被称为线程. 进程是表示资源分配的基本单位,线程是进程中执行运算的最小单位,亦是调度运行的基本单位. 举个例子: 打开你的计算机上的任务管 ...
- Java多线程学习(四)等待/通知(wait/notify)机制
转载请备注地址:https://blog.csdn.net/qq_34337272/article/details/79690279 系列文章传送门: Java多线程学习(一)Java多线程入门 Ja ...
随机推荐
- javaScript类型和对象
javaScript基本数据类型 Undefined: Null: Boolean: String: Number: Symbol: Object. 注意 JavaScript 的代码 undefin ...
- 使用 git 将代码推送到多个仓库
使用 git 将代码推送到多个仓库 起因 起初,在 GitHub 建了一个仓库,200+ 的 commits .后来(终于在眼泪中明白...误
- cogs 1440. [NOIP2013]积木大赛 贪心水题
1440. [NOIP2013]积木大赛 ★★ 输入文件:BlockNOIP2013.in 输出文件:BlockNOIP2013.out 简单对比时间限制:1 s 内存限制:128 M ...
- Spring Cloud Eureka------详解
一 Eureka服务治理体系 1.1 服务治理 服务治理是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册和发现. Spring Cloud Eureka是Spring Cl ...
- Java.数据结构.集合体系详解
I. 第一部分:常见数据结构 首先简单说下数据结构. 什么是数据结构?数据结构就是组织数据的方式. 常见的数据结构:栈,堆,树,图,数组,队列,链表. 这里主要介绍与java集合体系相关的栈.数组和链 ...
- [bzoj2115] [洛谷P4151] [Wc2011] Xor
Description Input 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 ...
- elasticsearch(lucene)索引数据过程
倒排索引存储-分段存储(lucene的功能)在lucene中:lucene index包含了若干个segment在elasticsearch中:index包含了若干主从shard,shard包干了若干 ...
- exp2:// 一次存储型XSS从易到难的挖掘过程
一日在某站点发现一个找茬活动,感觉是另类的src就参与了一下.就发生了这次有趣的XSS测试过程. 0×00 开始 (注意1)XSS不仅存在于页面上直观所在的位置,所有用户输入的信息都有可能通过不同形式 ...
- Excel Application操作指南
概述 Application对象是Microsoft Office Excel 2007对象模型中最高级别的对象,表示Excel程序自身.Application对象提供正在运行的程序的信息.应用于程序 ...
- 夜晚 十点 React-Native 源码 暴力畜 系列
百度 上 给的 关于 React-Native 的 排名 前三 继续 跟