`
alanlg
  • 浏览: 9885 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

项目开发中碰到的一个线程问题 (二)

阅读更多
         前几天碰到了一个问题项目开发中碰到的一个线程问题(一),当时说的不太清楚 ,这里好好总结下。
         现象:多线程Http请求,在服务端发现总会有相同参数的请求。当时认为是HttpClient在多线程下是线程非安全的,wangzhangxing 提到:
引用
PoolingClientConnectionManager cm = new PoolingClientConnectionManager();
cm.setMaxTotal(100);
然后new DefaultHttpClient(cm));
这样出来的client就是线程安全的了

         事实上代码里也确实是这么做的:
  /**
     * 初始化HttpClient对象
     * 
     * @return HttpClient对象
     */
    private HttpClient getHttpClient()
    {
        HttpClient httpClient = null;
        try
        {
            // ThreadSafeClientConnManager\PoolingClientConnectionManager
            PoolingClientConnectionManager pccm = new PoolingClientConnectionManager(getSchemeRegistry());
//            pccm.setDefaultMaxPerRoute(20);
            httpClient = new DefaultHttpClient(pccm, prepareHttpParams());
        }
        catch (Exception e)
        {
            e.printStackTrace();
            httpClient = new DefaultHttpClient();
        }
        return httpClient;
    }

        自己又认真狠看了几遍代码,其中的调用顺序是这样的,DataServiceImpl 是具体的业务实现类,通过HttpHelper对象获取服务端的信息。
package org.okura.timer;

/**
 * 服务接口实现类
 * 
 * @author okura
 * @since 2012-10-10
 */
public class DataServiceImpl implements IDataService
{
    private HttpHelper httpHelper;

    public DataServiceImpl()
    {
        httpHelper = new HttpHelper();
    }

    @Override
    public void getProduct(String type, String date)
    {
        // System.out.println(Thread.currentThread().getName() +
        // "---DataServiceImpl---type:" + type +",date:" + date);
         httpHelper.requestString(HttpUrlUtil.getProductUrl(type, date));
//         System.out.println("type:" + type +",date:" + date + "--" + response);
    }

}

HttpHelper代码,其中有些方法省略,详细代码可以下载附件查看
public class HttpHelper
{
    /** Http请求方法对象 */
    private HttpRequestBase request;

    /**
     * 发送Http请求,返回文本形式的请求响应
     * 
     * @param url url地址
     * @return
     */
    public String requestString(String url)
    {
        try
        {
            HttpResponse stringResponse = send(url);
            // 判断请求是否成功
            if (!isResponseSuccessStatus(stringResponse))
            {
                return null;
            }
            System.out.println(Thread.currentThread().getName() + "---url:" + url);
            return parseHttpResponse2String(stringResponse);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.out.println("requestString()" + url);
            return null;
        }
    }

    /**
     * 发送Http请求,返回请求响应
     * 
     * @param url url地址
     * @return
     */
    private HttpResponse send(String url) throws Exception
    {
        try
        {
            // 初始化Http请求方法和参数
            initGet(url);
            // 进行Http请求
            return doRequest();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            throw new Exception("http send request exception");
        }
    }

    /**
     * Get方法
     * 
     * @param url
     */
    private void initGet(String url)
    {
        request = new HttpGet(url);
    }

    /**
     * 初始化HttpClient对象
     * 
     * @return HttpClient对象
     */
    private HttpClient getHttpClient()
    {
        HttpClient httpClient = null;
        try
        {
            //ThreadSafeClientConnManager\PoolingClientConnectionManager
            httpClient = new DefaultHttpClient(new PoolingClientConnectionManager(getSchemeRegistry()),
                    prepareHttpParams());
        }
        catch (Exception e)
        {
            e.printStackTrace();
            httpClient = new DefaultHttpClient();
        }
        return httpClient;
    }

    /**
     * 进行Http请求,得到Http响应
     * 
     * @return Http响应
     * @throws Exception
     */
    private HttpResponse doRequest() throws Exception
    {
        HttpClient httpClient = getHttpClient();
//        setProxy(httpClient);// 设置代理
        return httpClient.execute(request);
    }
}

从上面代码可以看到,HttpHelper对象是DataServiceImpl 的全局变量,虽然HttpHelperHttpClient是通过PoolingClientConnectionManager 获取HttpClient的,没有进行同步操作,在多线程就很可能会出现获取出来的对象是相同的,(个人理解),这里抛砖引玉,哪位牛人帮详解下,^_^。
        那接下来怎么修改呢,很简单,只修改HttpHelper中的HttpClient变量使用范围:
public class HttpHelper
{
    /** HttpClient对象 */
    private HttpClient httpClient;

    /**
     * 构造函数
     */
    public HttpHelper()
    {
        httpClient = getHttpClient();
    }

    /**
     * 发送Http请求,返回文本形式的请求响应
     * 
     * @param url url地址
     * @return
     */
    public String requestString(String url)
    {
        HttpGet request = null;
        try
        {
            // 初始化Http请求方法和参数
            request = new HttpGet(url);
            // 进行Http请求
            HttpResponse stringResponse =  httpClient.execute(request);
            // 判断请求是否成功
            if (!isResponseSuccessStatus(stringResponse))
            {
                return null;
            }
            System.out.println(Thread.currentThread().getName() + "---url:" + url);
            return parseHttpResponse2String(stringResponse);
        }
        catch (Exception e)
        {
            request.abort();
            httpClient.getConnectionManager().shutdown();
            e.printStackTrace();
            System.out.println("requestString()" + url);
            return null;
        }
    }

    /**
     * 初始化HttpClient对象
     * 
     * @return HttpClient对象
     */
    private HttpClient getHttpClient()
    {
        try
        {
            // ThreadSafeClientConnManager\PoolingClientConnectionManager
            PoolingClientConnectionManager pccm = new PoolingClientConnectionManager(getSchemeRegistry());
            // pccm.setDefaultMaxPerRoute(20);
            httpClient = new DefaultHttpClient(pccm, prepareHttpParams());
        }
        catch (Exception e)
        {
            e.printStackTrace();
            httpClient = new DefaultHttpClient();
        }
        return httpClient;
    }
}


      有几点自己以后要注意:
       1、要注意代码细节,多测试才能发现问题。
       2、程序引用的代码即使不能钻研的很明白,至少能理解使用的具体场合。
       3、最重要的一点,以后要恶补基础啦, 三天不学习,不知道南北极哪,
       
分享到:
评论
1 楼 Reset 2013-03-19  
哥表示 被你的描述成功搞晕了

相关推荐

    TCP-接收线程和发送线程

    在这个项目中,“TCP-接收线程和发送线程”是一个C/C++实现的多线程编程示例,旨在展示如何在服务器端和客户端之间有效地管理数据的接收和发送。以下将详细介绍相关的知识点。 首先,我们要理解TCP的基本原理。TCP...

    基本情况 在一个项目开发过程中,遇到了小票自动打印的业务需求,原本计划使用NodeJS构建打印服务,调用本地电脑打印机进行数据打

    基本情况 在一个项目开发过程中,遇到了小票自动打印的业务需求,原本计划使用NodeJS构建打印服务,调用本地电脑打印机进行数据打印,最后可参考资料偏少,由于项目紧急且对NodeJS的熟悉程度目前也还不够,所以转而...

    文件打印问题 (c++多线程实现)

    在“文件打印问题”中,可能会遇到的一个关键问题是资源竞争。当多个线程尝试同时访问和修改同一个文件时,如果没有适当的同步机制,结果可能会是数据不一致或错误。为了解决这个问题,C++提供了如互斥量(mutex)、...

    多线程串口通讯实例,基于VC++开发

    在这个实例中,你将找到一个已经实现的多线程串口通信程序。打开项目后,你可以看到源代码,其中可能包含了如何初始化串口、设置参数、读写数据以及处理多线程同步的示例。注释部分会帮助理解各个函数和结构的作用,...

    多线程下载器.zip易语言项目例子源码下载

    本文将深入剖析一个基于易语言实现的多线程下载器项目,旨在帮助个人学习者、学生以及小团队开发者理解并掌握这一技术。 首先,我们要明确什么是多线程下载。传统的单线程下载方式中,数据是顺序地从服务器读取到...

    WIN10_VS2019_配置_多线程_C语言.docx

    这里主要介绍如何配置VS2019以便支持C语言的多线程功能,以及解决在配置过程中可能遇到的问题。 首先,我们需要明白,多线程在C语言中通常是通过POSIX线程库(pthread)来实现的,但在Windows系统上,原生的API是...

    线程操作,可多线程

    5. **错误处理**:线程操作中难免会遇到错误,如创建失败、同步问题等,自定义线程类应有适当的错误处理机制。 6. **状态管理**:线程的运行状态(如是否正在运行、是否已结束等)也需要被管理,以便在代码中正确地...

    鱼刺多线程模块

    总的来说,"鱼刺多线程模块"为开发者提供了一个强大的工具,使他们能够在软件开发中充分利用多核处理器的优势,提升程序性能。通过理解和掌握这个模块,开发者可以创建更加高效、响应迅速的应用程序,同时也能深入...

    Indy多线程程序客户端演示程序

    Indy(Internet Direct)是Delphi和C++Builder开发网络应用程序的一个强大库,它提供了丰富的组件集合,用于实现各种网络协议,如TCP/IP、HTTP、SMTP、FTP等。本示例程序“Indy多线程程序客户端演示程序”旨在演示...

    C++名家对话(项目中常见问题解决方案)

    "C++名家对话(项目中常见问题解决方案)"这一主题,聚焦于C++在实际项目中的应用,探讨了设计模式、惯用法以及如何解决遇到的问题。下面我们将深入探讨这些关键知识点。 首先,设计模式是软件工程中的通用解决方案...

    java开发常见问题

    java开发工作两年遇到的技术问题以及查找到的解决方案还有一些积累,涉及前端技术,android开发,java后台以及数据库sql优化,session共享,单点登录,kafka入门,websocket,线程安全等。

    Java案例开发_项目开发风暴(含源代码)

    通过"Java案例开发_项目开发风暴"中的实战项目,你可以将上述知识点逐一实践,从而深入理解并掌握Java项目开发的全过程。每个项目都可能涉及上述部分或全部知识点,通过不断地练习和调试,你的编程技能和问题解决...

    在列表控件中采用多线程技术插入进度条

    在开发Windows应用程序时,我们经常会遇到需要处理大量数据并实时更新UI的情况,比如在一个列表控件(ListCtrl)中显示大量的信息。在这个过程中,如果在主线程中进行操作,可能会导致界面卡顿,用户体验下降。为了...

    Iphone下多线程的开发

    ### IPhone下多线程的开发 随着移动设备性能的不断提升以及用户对应用程序功能和响应速度的要求越来越高,多线程编程已经成为iOS应用开发中的一个重要组成部分...希望本文对你在实际项目中遇到的多线程问题有所帮助。

    一个基于java的多线程爬虫项目.zip

    在IT领域,尤其是在Web开发和数据获取中,爬虫项目是一个重要的组成部分。本项目是一个基于Java的多线程爬虫实现,它展示了如何利用Java语言高效地抓取互联网上的信息。下面将详细介绍这个项目的相关知识点。 1. **...

    多线程雷电游戏

    10. **源码分析**:博客中提供的源码可能是分析的重点,通过阅读和学习,读者可以了解到实际项目中如何设计和实现一个多线程游戏。 综上所述,"多线程雷电游戏"涉及了软件工程、操作系统、编程语言、游戏开发等多个...

    易语言超线程下载源码.zip易语言项目例子源码下载

    对于个人学习者、学生毕业设计或小团队项目来说,这个易语言超线程下载源码是一个很好的实践案例,可以学习到如何结合易语言的特性,实现高效的多线程网络下载,同时还能涉及到线程同步、错误处理、资源管理等多个...

    易语言多线程传递文本参数两种方法源码

    易语言多线程传递文本参数是开发中常常遇到的问题,下面将详细介绍两种常见的方法。 **方法一:使用全局变量** 易语言中,全局变量可以在程序的不同线程间共享数据,因此可以用来传递参数。这种方式简单直接,但...

    C#开发的基于Socket的多线程服务器端短信转发程序

    本项目是一个基于C#的多线程服务器端短信转发程序,它利用Socket技术实现高效的信息处理和并发能力,适合大规模并发场景。下面将详细阐述这个程序的核心知识点。 1. **C#编程基础**:C#是微软推出的面向对象的编程...

Global site tag (gtag.js) - Google Analytics