繁体   English   中英

TimerTask挂起

[英]TimerTask hangs

我试图通过Java中的TimerTask功能从main()启动周期任务,并且run()任务挂起。 计时器之后的代码是REPL。 代码如下:

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的响应。 实际上,发生的是“从...检索数据”消息出现一次,然后任务挂起。 如果使用REPL,请在StdIn上键入命令,然后在stdout中出现“连接超时”错误。

因此,TimerTask似乎与REPL(在读取行中被阻止)发生冲突。 这是怎么回事?

java.util.TimerTask只有线程可以运行任务。 如果一项任务继续运行,则其他任务必须等待完成。 您可以将其替换为java.util.concurrent.ScheduledExecutorService ,它可以启动更多线程来运行任务...

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

    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() );

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

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

在我的情况下,发生的事情是REPL在BufferedReader.readLine()上阻塞,因此streamHandlerLock被冻结。 因此,当openConnection执行时,它将在此对象上死锁。

(我可以在这里说一下詹姆斯·高斯林(James Gosling)的编码技巧,他设计并编写了这个令人厌烦的系统,并在源代码上签名了他的名字,或者我可以说一些Sun Oak团队完全失败的原因,因为Java重写了这个垃圾在16年前的2000年成为主流,但我想我会把它留给读者我想说的话。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM