`
alanlg
  • 浏览: 9670 次
  • 性别: 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  
哥表示 被你的描述成功搞晕了

相关推荐

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

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

    java开发常见问题

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

    Android实战开发租赁管理软件(适配UI,数据的存储,多线程下载)

    在开发中,大家讲学习到基本的组件,适配UI,数据的存储,多线程下载,开机广播,闹钟提醒,短信发送等实际项目开发中碰到的有用的知识点。通过课程学习,让大家能够掌握Android软件开发的流程,注意点,及优化。...

    基于QT和C++开发的仿win10的任务管理器项目源码+项目说明(操作系统课设).zip

    无论您是运行还是二次开发,部署过程若遇到问题,请及时私信交流,欢迎学习。 基于QT和C++开发的仿win10的任务管理器项目源码+项目说明(操作系统课设).zip 功能模块 ![功能模块](img/module.png) * 仿照Windows10...

    java项目总结报告.pdf

    本资源是一个非常详细和实用的 Java 项目总结报告,涵盖了项目管理、Java 语言、数据库设计、需求分析、表单设计、数据校验、分页和批量删除、团队合作、问题解决等方面的内容,对于 Java 项目开发和软件工程有很大...

    Linux下使用tomcat发布Web项目

    Tomcat 是一个开源的 Web 服务器软件,广泛应用于 Java Web 开发中。在 Linux 系统下,Tomcat 可以轻松地安装和配置,以便发布 Web 项目。 Linux 系统的特点 Linux 是一个免费、开源的操作系统,具有多线程、多...

    Visual C++开发实例大全 提高卷.part5

    《Visual C 开发实例大全(提高卷)》以开发人员在项目开发中经常遇到的问题和必须掌握的技术为核心,介绍了应用Visual C 进行程序开发各个方面的知识和技巧,主要包括Windows操作、鼠标和键盘相关、注册表、线程和...

    Visual C++开发实例大全 提高卷.part2

    《Visual C 开发实例大全(提高卷)》以开发人员在项目开发中经常遇到的问题和必须掌握的技术为核心,介绍了应用Visual C 进行程序开发各个方面的知识和技巧,主要包括Windows操作、鼠标和键盘相关、注册表、线程和...

    Android项目高手过招 FAQ.rar

    《Android项目高手过招FAQ》是一本专为Android开发者打造的实用指南,旨在解决他们在开发过程中遇到的各种常见问题。本书汇集了大量实战经验和技巧,以Q&A的形式呈现,方便读者快速查找和解决问题。 本书涵盖了...

    Linux内核的栈使用,问题的定位

    例如,在一个项目中,笔者遇到过一个死循环的问题,使用 sysrq 的内核线程栈回溯功能终于找到死循环的函数。在另一个项目中,应用程序发生了 double free,运用内核的栈回溯功能,找到应用代码哪里发生了 double ...

    java即时通讯项目

    使用JavaSE实现即时通讯项目,适合有一定的Java基础的用户编写,主要用到多线程...代码部分我添加了大量的注册,并且加了一些我在开发的过程中遇到的问题,都用特殊标记标注出来了,以此来警告自己下次不犯类似的错误。

    安卓开发的期末项目,以二十四节气为主题的论坛贴

    安卓开发的期末项目,以二十四节气为主题的论坛贴。用安卓的布局作为前端,SpringBoot作为后端。 登录界面: 登录首先需要把sql中原有的数据清空,因为该校验先会在前端的内存数据进行校验的,校验完成之后才会校验...

    JAVA上百实例源码以及开源项目源代码

     用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...

    [你必须知道的222个C++语言问题].范立锋.扫描版[ED2000.COM]-第四部分

    本书精选了222个在C++程序设计中经常遇到的问题和典型功能,覆盖了实际开发中的各种需求,目的是帮助读者解决在C++学习和开发中经常遇到的实际问题,同时提高学习和开发的效率。本书涵盖了C++与C语言的区别和联系、...

    [你必须知道的222个C++语言问题].范立锋.扫描版[ED2000.COM]-第三部分

    本书精选了222个在C++程序设计中经常遇到的问题和典型功能,覆盖了实际开发中的各种需求,目的是帮助读者解决在C++学习和开发中经常遇到的实际问题,同时提高学习和开发的效率。本书涵盖了C++与C语言的区别和联系、...

    Visual C++开发实例大全 提高卷.part1

    《Visual C 开发实例大全(提高卷)》以开发人员在项目开发中经常遇到的问题和必须掌握的技术为核心,介绍了应用Visual C 进行程序开发各个方面的知识和技巧,主要包括Windows操作、鼠标和键盘相关、注册表、线程和...

    Visual C++开发实例大全 提高卷.part4

    《Visual C 开发实例大全(提高卷)》以开发人员在项目开发中经常遇到的问题和必须掌握的技术为核心,介绍了应用Visual C 进行程序开发各个方面的知识和技巧,主要包括Windows操作、鼠标和键盘相关、注册表、线程和...

    Visual C++开发实例大全 提高卷.part3

    《Visual C 开发实例大全(提高卷)》以开发人员在项目开发中经常遇到的问题和必须掌握的技术为核心,介绍了应用Visual C 进行程序开发各个方面的知识和技巧,主要包括Windows操作、鼠标和键盘相关、注册表、线程和...

Global site tag (gtag.js) - Google Analytics