首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TimerTask挂起

TimerTask挂起
EN

Stack Overflow用户
提问于 2016-02-09 23:37:06
回答 2查看 726关注 0票数 0

我试图通过Java中的TimerTask功能从main()启动一个周期任务,但run()任务挂起了。定时器之后的代码是一个REPL。代码如下所示:

代码语言:javascript
复制
public static void main( String[] asArguments ){
    java.util.Timer timer = new Timer();
    long durationDelay_ms = 60*60*1000; // 1 hour
    long durationPeriod_ms = 60*60*1000; // 1 hour
    timer.scheduleAtFixedRate(  // reload prices every hour
        new TimerTask() {
            @Override
            public void run() {
                StringBuffer sbError = new StringBuffer();
                if( ! reload( false, sbError ) ){
                    System.out.println( "error reloading prices: " );
                }
                sbError = null; // garbage collect
            }
    }, durationDelay_ms, durationPeriod_ms );

    // REPL
    BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
    while( true ){
        System.out.print( "> " );
        try {
            String s = br.readLine();
            \\ ... code to process command
        } catch( Throwable t ) {
            \\ handle error 
        }
    }
}

public static final boolean reload( ){
    for( int i = 1; i <= 4; i++ ){
        String sURL = "c:\\xyz.com\\" + i; \\ URL I am reading from
        System.out.println( "retrieving data from:\n" + sURL );
        StringBuffer sb = new StringBuffer( 10000 );
        try {
            URL url = new URL( sURL );
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            sb = readStream( con.getInputStream() );
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    System.out.println( sb.toString() );
}

该任务尝试建立多个URL连接,并打印出每个URL连接的响应。在实践中发生的情况是“从...检索数据”消息出现一次,则该任务显示为挂起。如果我通过在StdIn中键入命令来使用REPL,那么在标准输出中就会出现"connection timed out“错误。

因此,TimerTask似乎与REPL (在readline上阻塞)有冲突。这是怎么回事?

EN

回答 2

Stack Overflow用户

发布于 2016-02-10 00:38:51

java.util.TimerTask只有运行任务的线程。如果一个任务继续运行,其他任务必须等待,直到它完成。你可以用java.util.concurrent.ScheduledExecutorService代替它,它可以启动更多的线程来运行任务……

我猜你尝试连接的URL需要一些“输入”,所以它在等待额外的数据……尝试修改源代码并为其提供一些数据。例如:

代码语言:javascript
复制
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setConnectTimeout(5000);//not required
    con.setDoOutput(true);
    con.setDoInput(true);
    OutputStream out = con.getOutputStream();
    out.write("&param1=a&param2=b".getBytes());
    out.close();
    sb = readStream( con.getInputStream() );
票数 0
EN

Stack Overflow用户

发布于 2016-02-10 21:11:53

我最终发现了问题所在。Java方法的实现在一个名为streamHandlerLock的内部对象上进行同步,该对象由一组不同的内部HttpURLConnection库共享,包括缓冲的读取库。

这基本上意味着您不能在多个并发线程中使用使用java.net或java.io的任何基于流的IO。

在我的例子中,发生的情况是REPL阻塞了BufferedReader.readLine(),所以streamHandlerLock被冻结了。因此,当openConnection执行时,它会在这个对象上发生死锁。

(我可以在这里谈谈James Gosling的编码技巧,他设计和编写了这个拦截系统,并在源代码上签名,或者我可以说Sun Oak团队在16年前的2000年Java成为主流时重写这些垃圾代码的彻底失败,但我想我会让读者想象我可能会说什么。)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35296017

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档