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

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多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析的更多相关文章

  1. 【Java并发编程】:使用wait/notify/notifyAll实现线程间通信

    在java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信.在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调 ...

  2. 二、java多线程编程核心技术之(笔记)——如何停止线程?

    1.异常法 public class MyThread extends Thread { @Override public void run() { super.run(); try { for (i ...

  3. Java多线程编程核心技术(三)多线程通信

    线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时 ...

  4. java多线程编程核心技术——第三章

    第一节等待/通知机制 1.1不使用等待/通知机制实现线程间的通讯 1.2什么是等待/通知机制 1.3等待/通知机制的实现 1.4方法wait()锁释放与notify()锁不释放 1.5当interru ...

  5. java多线程编程核心技术——第三章总结

    第一节等待/通知机制 1.1不使用等待/通知机制实现线程间的通讯 1.2什么是等待/通知机制 1.3等待/通知机制的实现 1.4方法wait()锁释放与notify()锁不释放 1.5当interru ...

  6. 《Java多线程编程核心技术》读后感(八)

    不使用等待/通知机制实现线程间通信 使用sleep()结合while(true)死循环来实现多个线程间通信 package Third; import java.util.ArrayList; imp ...

  7. Java多线程编程核心技术

    Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...

  8. Java多线程编程核心技术(一)Java多线程技能

    1.进程和线程 一个程序就是一个进程,而一个程序中的多个任务则被称为线程. 进程是表示资源分配的基本单位,线程是进程中执行运算的最小单位,亦是调度运行的基本单位. 举个例子: 打开你的计算机上的任务管 ...

  9. Java多线程学习(四)等待/通知(wait/notify)机制

    转载请备注地址:https://blog.csdn.net/qq_34337272/article/details/79690279 系列文章传送门: Java多线程学习(一)Java多线程入门 Ja ...

随机推荐

  1. C语言之数组用法总结

    一维数组的定义:1.数组的数据类型:每一元素占内存空间的字节数.2.数组的存储类型:内存的动态. 静态存储区或CPU的寄存器.3.一维数组在内存中占用的字节数为:数组长度X sizeof (基类型). ...

  2. UGUI ScrollView中显示模型和特效

    游戏开发中有时候会遇到在UI上显示模型和特效的需求,这次需要在ScrollView上显示.我们使用UGUI的Screen Space - Camera模式,修改模型和特效的layer使之显示在UI上面 ...

  3. bzoj 2683 CDQ分治

    题目描述 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 将格子x,y里的数 ...

  4. 关于在读取excel的文件时候,放在服务器上就报路径错误

    就是指定这个路径:C:\Program Files (x86)\IIS Express 因为在上传到服务器的时候,服务器读取的是在服务器上的路径,所以正确的思路应该是 把上传的Excel存在服务器上, ...

  5. 安装SQL的时候,设置用户权限失败

    在安装sql的时候,遇到一个问题: 在查看报表明细中,提示: 就是这三个: 首先确保你是使用管理员用户安装的,如果还不行,运行 secpol.msc 进入本地安全策略 把自己的用户名加入进来就好了.

  6. Browser Security-基本概念

    URL格式: scheme://[login[:password]@](host_name|host_address)[:port][/hierarchical/path/to/resource[?s ...

  7. 20200104模拟赛 问题A 图样

    题目 分析: 老规矩,遇到期望要准备好随时投降... 大致想到了按位处理,然后分别下去搜索,再用组合数加加减减一下... 但是两个连通块之间连边的期望怎么算呢? 很好,投降... 下来看题解... 果 ...

  8. 20191217HNOI 模拟赛 复活石

    题目描述: 分析: 我也不知道我在干sm,但就是没写出来2333 枚举 i 的每个质因子 j ,复杂度为n^(3/2) 为什么我会认为是n^2啊2333 然后考虑 f ( j )对g ( i )做了多 ...

  9. NOI4.6 最小新整数——切山游戏

    描述 给定一个十进制正整数n(0 < n < 1000000000),每个数位上数字均不为0.n的位数为m. 现在从m位中删除k位(0<k < m),求生成的新整数最小为多少? ...

  10. python3操作MySQL的模块pymysql

    本文介绍Python3连接MySQL的第三方库--PyMySQL的基本使用. PyMySQL介绍 PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中 ...