首页 技术 正文
技术 2022年11月8日
0 收藏 612 点赞 1,375 浏览 2576 个字

不使用等待通知机制 实现线程间通信的 疑问分析

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线程抛出异常,停止运行。

《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析

但是实际上本地运行结果如下,没有抛出异常:B线程还是一直在进行while循环

《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析

这让我十分困惑。就进行各种测试,我在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运行结束,虚拟机也停止运行了。如图:

《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析

只是添加了一句打印的代码,竟然会影响程序的执行逻辑???这是什么原因?另外,我又继续做了如下测试:

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线程循环输出完毕,虚拟机不停。

《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析

继续,在B线程  if  分支处打断点,debug运行来看,控制台一直在运行打印输出A添加了x个元素,证明A线程在一直跑,没错。B中Size也是在变化的,可是当size等于if条件语句中的值(5)时,却没有进入if代码块里面去执行,所以抛出异常又从何谈起呢?

而且,今晚我又发现,if语句中list.size == 1时,能实现效果,如下图:

《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析

当  list.size == 其他数值时,比如原文中的 5、又比如自己尝试的6、7、4、3等,均不行。如图:

《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析

但此时,如果添加上面所说的输出语句,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的内容,效果如下图,是可以实现目的  的。

《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析

或者改成直接锁list也是同样的道理

《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析

上面就是我所发现的分析过程,希望大佬能够不吝赐教,分析一下原因。感激不尽,谢谢。

============20190414===========

这个问题今年前一段时间,再次看到这里,我又写了一些demo小例子,进行一些验证。其实也没有什么难理解的,其实就是变量在县城之间的可见性问题。感觉书中的代码有些不严谨。。。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,492
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,494
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,132
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,295