[英]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("¶m1=a¶m2=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.