`
ironlee
  • 浏览: 1224 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

《JAVA多线程编程核心技术》3.1.10的错误纠正

阅读更多
我看的书作者:高洪岩

书版本:2015年11月第1版第3次印刷

问题概述:

3.1.10 主要讲解 等待wait的条件发生变化的场景

为了方便起见,我就不照抄书中原码了,我用我自己的代码 就是一个main方法 我用的jdk1.6

public static void main(String[] args) throws InterruptedException {
        final List<String> list = new ArrayList<String>();
        final Object lock = new Object();
//        等待&删除
        Runnable waitRun = new Runnable() {
            @Override
            public void run() {
                synchronized( lock ){
                    try {
                        if( list.size() == 0 ){
                            System.out.println("wait begin t="+Thread.currentThread().getName());
                            lock.wait();
                            System.out.println("wait end"+Thread.currentThread().getName());
                        }
                        System.out.println("list remove begin"+Thread.currentThread().getName());
                        list.remove( 0 );
                        System.out.println("list remove end "+Thread.currentThread().getName() + " size="+list.size());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
//        唤醒&增加
        Runnable notifyRun = new Runnable() {
            @Override
            public void run() {
                synchronized( lock ){
                    System.out.println("list add");
                    list.add( "1" );
                    System.out.println("notify begin");
                    lock.notifyAll();
                    System.out.println("notify end");
                }
            }
        };
        //线程1-删除操作 锁等待
        Thread waitT1 = new Thread( waitRun );
        waitT1.start();
        //线程2-删除操作 锁等待
        Thread waitT2 = new Thread( waitRun );
        waitT2.start();
        Thread.sleep( 1000L );
        //线程3-增加操作 唤醒所有等待
        Thread notifyT1 = new Thread( notifyRun );
        notifyT1.start();
    }

这样有个问题就如书中据说 会有一个删除操作 异常 因为已无元素可删。

Exception in thread "Thread-0" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0

书中给出的解决方案是这样的

是在删除线程中 while(list.size==0) 这样可以保证在有元素的时候执行删除操作。

//        等待&删除
        Runnable waitRun = new Runnable() {
            @Override
            public void run() {
                synchronized( lock ){
                    try {
//                      此处是修改点 由原来的if 改成 while
                        while( list.size() == 0 ){
                            System.out.println("wait begin t="+Thread.currentThread().getName());
                            lock.wait();
                            System.out.println("wait end"+Thread.currentThread().getName());
                        }
                        System.out.println("list remove begin"+Thread.currentThread().getName());
                        list.remove( 0 );
                        System.out.println("list remove end "+Thread.currentThread().getName() + " size="+list.size());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

这样确实保证了有元素时才删除,因为当你无元素时,会一直循环wait()操作。

但这有个问题是第二个删除线程 因为集合已无元素删除了,会多一个wait,而这个wait()是在notifyAll之产生的,会永远唤醒不了。

所以这个做法属于解决了旧问题,又产生新的问题。

而我的做法是这样的
Runnable waitRun = new Runnable() {
            @Override
            public void run() {
                synchronized( lock ){
                    try {
                        System.out.println("wait begin t="+Thread.currentThread().getName());
                        lock.wait();
                        System.out.println("wait end"+Thread.currentThread().getName());
//                        是否执行过删除 
                        boolean deleteFlag = false;
                        System.out.println( "list size="+list.size() +" remove before");
                        while( list.size() > 0 && deleteFlag == false ){
                            System.out.println("list remove begin"+Thread.currentThread().getName());
                            list.remove( 0 );
                            System.out.println("list remove end "+Thread.currentThread().getName() + " size="+list.size());
                            deleteFlag = true;
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

思路是这样的,不能在wait()动手脚,转移到删除元素上,循环list.size >0 && 没有执行过操作 才执行删除并且只能执行一次 这样就解决了这个问题了。

总结

遇到wait条件变化时,基本思路就是用while的方法让线程一直处于等待,待条件满足时才执行下一步。
分享到:
评论

相关推荐

    mysql-connector-java-3.1.10.zip

    MySQL Connector/J是MySQL数据库系统与Java应用...随着技术的发展,后续版本的MySQL Connector/J可能会包含更多特性,改进性能和兼容性,但3.1.10版本对于那些仍使用旧版MySQL服务器的项目来说,仍是一个可靠的选项。

    mysql-connector-java-3.1.10.tar.tar

    mysql-connector-java-3.1.10.tar.tarmysql-connector-java-3.1.10.tar.tarmysql-connector-java-3.1.10.tar.tar

    resin-3.1.10

    在升级到更现代的版本之前,使用Resin 3.1.10的老系统可能会遇到一些挑战,比如对新Java和Web技术的支持不足、安全性可能落后以及可能存在的bug。然而,对于那些依赖旧版软件的环境,Resin 3.1.10仍能提供稳定的运行...

    java 编程入门思考

    1.9 多线程 1.10 永久性 1.11 Java和因特网 1.11.1 什么是Web? 1.11.2 客户端编程 1.11.3 服务器端编程 1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段...

    libmodbus-3.1.10

    - **版本号**:3.1.10表明这是libmodbus库的一个稳定版本,可能包括错误修复、性能优化和新功能的添加。 - **源码包**:提供`.tar.gz`和`.zip`两种格式的源码包,用户可以根据自身系统环境选择合适的方式进行编译...

    smarty3.1.10

    10. **调试与错误处理**:Smarty提供了调试模式,可以帮助开发者追踪模板错误,输出编译后的模板代码,以便于调试和优化。 在"Smarty-3.1.10"这个压缩包中,内含的"demo"可能包含了示例代码和说明,帮助初学者快速...

    apache - cfx -3.1.10

    CXF支持多种数据绑定技术,如Java Architecture for XML Binding (JAXB)和XMLBeans,用于自动将XML数据转换为Java对象,反之亦然。这使得处理XML数据变得直观且高效。 **5. 安全性** CXF提供了对WS-Security和其他...

    Thinking in Java 中文第四版+习题答案

    1.9 多线程 1.10 永久性 1.11 Java和因特网 1.11.1 什么是Web? 1.11.2 客户端编程 1.11.3 服务器端编程 1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段...

    libmodbus 3.1.10 vs2017 windows x86编译

    总结,libmodbus 3.1.10的编译过程涉及了多个步骤,包括环境配置、源码获取、CMake配置、VS项目生成及编译等。虽然可能遇到一些问题,但只要按照正确步骤操作,并解决可能出现的依赖问题,就能顺利编译出所需的库...

    SAP Java JCo 3.1.10 Windows 平台 32bit / 64bit

    SAP Java JCo 3.1.10 Windows 平台 32bit / 64bit The SAP Java Connector (SAP JCo) is a development library that enables a Java application to communicate with SAP systems via SAP's RFC protocol. The ...

    jdom-b3.1.10

    JDOM-b3.1.10是该库的一个特定版本,带来了多项优化和改进,以适应不断发展的编程需求。 首先,我们来理解JDOM的核心概念。JDOM将XML文档映射为一系列的Java对象,如Element(元素)、Attribute(属性)和Text...

    CodeIgniter-3.1.10.zip

    在CodeIgniter-3.1.10.zip文件中,包含了整个框架的源代码,包括核心类、库、辅助函数、模型、视图、控制器以及配置文件等。开发者可以通过研究这些源代码深入理解CI的工作原理,自定义框架行为,或者开发自定义库和...

    cas-client-core-3.1.10.jar

    可用 cas-client-core-3.1.10.jar

    demo3.1.10(GtkEntry).rar

    demo3.1.10(GtkEntry).rardemo3.1.10(GtkEntry).rardemo3.1.10(GtkEntry).rardemo3.1.10(GtkEntry).rardemo3.1.10(GtkEntry).rardemo3.1.10(GtkEntry).rardemo3.1.10(GtkEntry).rardemo3.1.10(GtkEntry).rardemo...

    php_apc-3.1.10-5.3-vc9-x86.rar

    3. 需要考虑是否开启线程安全,如果是在多线程环境中运行,应确保使用带“ts”后缀的版本。 4. 安装后,要检查PHP错误日志以排除任何可能的冲突或配置问题。 5. 调整APC的缓存策略,如命中率、缓存清理策略等,以...

    CXF3.1.10.jar

    【CXF3.1.10.jar】是一个与Apache CXF相关的Java库文件,它包含了CXF框架在3.1.10版本的所有组件和功能。Apache CXF是一个开源服务框架,它允许开发者构建和消费Web服务。这个jar包是开发人员在使用CXF框架时所必需...

    Dubbo服务框架 v3.1.10.zip

    6. **多语言支持**:除了Java,Dubbo还提供了对其他语言的支持,如Python、Go等,使得非Java项目也能方便地与Dubbo服务交互。 7. **与Spring集成**:Dubbo可以无缝集成到Spring框架中,使得配置和服务管理变得更加...

    CodeIgniter v3.1.10

    CodeIgniter 是一个小巧但功能强大的 PHP 框架,作为一个简单而“优雅”的工具包,它可以为 PHP 程序员建立功能完善的 Web 应用程序。如果你是一个使用共享主机,并且为客户所要求的期限而烦恼的开发人员,如果你...

    demo3.1.10(GtkEntry) (password).rar

    demo3.1.10(GtkEntry) (password).rardemo3.1.10(GtkEntry) (password).rardemo3.1.10(GtkEntry) (password).rardemo3.1.10(GtkEntry) (password).rardemo3.1.10(GtkEntry) (password).rardemo3.1.10(GtkEntry) ...

    接收NetFlow数据并导入Mysql数据库的Java工具

    标题中的“接收NetFlow数据并导入Mysql数据库的Java工具”指的是一个利用Java编程语言开发的应用,该应用能够处理从网络设备上收集的NetFlow数据,并将这些数据存储到MySQL数据库中。NetFlow是一种网络流量监测协议...

Global site tag (gtag.js) - Google Analytics