免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1125 | 回复: 0
打印 上一主题 下一主题

JAVA线程的超时处理 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-01-11 19:01 |只看该作者 |倒序浏览
网络编程经常遇到的一种情况是:客户端通过Socket与服务器通信时,遇到断断续续的数据流,有时接收线程可能因为无法收到完整的数据而发生长时间阻塞。在这种情况下,即使设置socket超时也不见得有效(例如,HttpClient中虽然可以设置socketTimeout,但以本人的经验来看,遇到这种线程阻塞的情况仍然束手无策)。例如,下面这段代码可能长时间阻塞在readLine():
BufferedReaderin = new BufferedReader(new InputStreamReader(get.getResponseBodyAsStream(),get.getResponseCharSet()));
StringinputLine = in.readLine();
while(inputLine != null) {
    resultBuffer.append(inputLine);
    resultBuffer.append("\n");
    inputLine = in.readLine();
}
in.close();

因此,必须想办法解决这种问题。

一种办法是调用JDK 1.2中提供的stop()方法强行终止线程,但此方法因为调用时线程内部的状态完全无法确定,已经被淘汰,不推荐使用。

当然,也可以查找一些现成的处理超时的Class,例如HttpClient中就提供了这样一个Class- TimeoutController(位于org.apache.commons.httpclient.util包内)查看该class的源代码可知其实现细节:
publicstatic void execute(Thread task, long timeout) throws TimeoutException {
        task.start();
        try {
       task.join(timeout);
        } catch (InterruptedException e) {
       /* if somebody interrupts us he knowswhat he is doing */
        }
        if (task.isAlive()) {
       task.interrupt();
       throw new TimeoutException();
        }
    }
其实就是通过join()和interrupt()方法实现这种功能,文档中强调了task的interrupt()方法必须重写(override),也就是说,这种方法还是无法保证线程超时结束时的状态稳定。

我们发现,问题的关键在于,如何保证线程超时关闭后进行相应的收尾工作。其实,这一点可以通过异常机制来解决:
提供给外部调用的关闭方法stopThread()首先检查输入流是否为空,如果不为空,则直接关闭输入流,此时从输入流读取数据的方法会捕捉到一个IOException异常,只要捕获了这个异常,就可以执行相应的收尾操作。

在线程中设置如下几个属性:
InputStreaminStream = null;
booleanisReady = false;
booleannoStopRequested = true;

在run()调用的方法中有如下代码:
……
try {
    client.executeMethod(get);
    inStream = get.getResponseBodyAsStream();
    String charSet = get.getResponseCharSet();
    InputStreamReader isReader = newInputStreamReader(inStream, charSet);
    BufferedReader buffIn = newBufferedReader(isReader);
    String inputLine = buffIn.readLine();
    while ((inputLine != null) &&noStopRequested) {
       resultBuffer.append(inputLine);
       resultBuffer.append("\n");
       inputLine = buffIn.readLine();
    }
    isReady = true;
} catch(IOException e) {
    //如果调用了stopThread()方法,就会捕获到IOException异常
    //此时noStopRequested为false,不用做任何处理
    if (noStopRequested) {
       e.printStackTrace();
    } else {
       //do nothing
    }
} finally{
    //分情况进行收尾工作
    try {
       if (noStopRequested) {
               inStream.close();
               inStream= null;
       }
       buffIn.close();
       isReader.close();
    } catch (Exception e) {
       e.printStackTrace();
    }
    if(isReady) {
       return resultBuffer.toString();
    } else {
       return "";
    }
    get.releaseConnection();
}
……

提供给外界调用的关闭方法:
publicvoid stopThread() {
    noStopRequested = false;
    if (inStream != null) {
       try {
           inStream.close();
       } catch (Exception e) {
                //
       } finally {
           inStream = null;
       }
    }
}

经过测试,这种技巧能有效地关闭超时线程。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/56194/showart_462504.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP