Java更多的库谜题82:啤酒爆炸

Java更多的库谜题82:啤酒爆炸,第1张

Java更多的库谜题82:啤酒爆炸,第2张

本章中的许多谜题涉及多线程,而这个谜题涉及多进程。如果您在命令行中使用参数slave运行这个程序,它会打印什么?如果您使用不带任何参数的命令行,它会打印什么?
public class beer blast {
static final String COMMAND = " Java beer blast slave ";
public static void main(String[]args)抛出异常{
if(args . length = = 1 & & args[0]。equals(" slave "){
for(int I = 99;I > 0;I-){
system . out . println(I+
"墙上的几瓶啤酒");
System.out.println(i +"瓶啤酒");
system . out . println(
“你拿下来,传一传,”);
system . out . println((I-1)+
"墙上的啤酒瓶");
system . out . println();
}
} else {
//Master
Process Process = runtime . get runtime()。exec(命令);
int exit value = process . wait for();
System.out.println("退出值= "+exit value);
}
}
}

如果使用参数slave运行程序,它会打印出名为“墙上的99瓶啤酒”的激动人心的童谣歌词,这并不神秘。如果你不用这个参数运行这个程序,它会启动一个从进程来打印这首歌谣,但是你看不到从进程的输出。主进程将等待从属进程完成,然后打印出从属进程的退出值。按照惯例,0值表示正常结束,所以0是您可能期望程序打印的内容。如果你运行程序,你可能会发现它只是挂在那里,不打印任何东西。看起来好像从属进程总是在运行。所以你可能会觉得你应该经常听到《墙上的99瓶啤酒》这首童谣,即使这首歌跑调了,但这首歌只有99句。而且计算机速度快,你假设的情况应该不存在。那么这个程序有什么问题呢?

这个秘密线索可以在Process类的文档中找到,文档中写道:“由于一些本地平台只提供有限大小的缓冲区,如果子进程的输出流没有被快速读取,可能会导致子进程的阻塞甚至死锁”[Java-API]。这里恰好发生了这样的事情:没有足够的buffer 空空间来保存这首冗长的歌谣。为了确保从属进程可以结束,父进程必须排出其输出流,从主线程的角度来看,这是输入流。以下工具方法将在后台线程中完成此操作:

static void drain background(final InputStream is){
new Thread(new Runnable(){
public void run(){
try {
while(is . read()> = 0);
} catch(io exception e){
//返回io exception
}
}
})。start();
}

如果我们在等待从属进程之前修改原始程序并调用此方法,程序将打印出0:

} else {//Master
Process Process = runtime . get runtime()。exec(命令);
drain background(process . getinputstream());
int exit value = process . wait for();
System.out.println("退出值= "+exit value);
}

这里的教训是:为了保证子进程能够结束,你必须对它的输出流进行排队空;对于error stream来说也是一样,可能会更麻烦,因为你无法预测进程什么时候会把一些输出转储到这个流中。在5.0版本中,名为ProcessBuilder的类被添加到这些流的队列空中。它的redirectErrorStream方法合并了所有的流,所以你只需要将这个流排队空。如果您决定不合并输出流和错误流,则必须并行排列空。尝试将它们按顺序排队空会导致子进程被挂起。

多年来,很多程序员都被这个缺陷刺痛过。这里给API设计者的教训是,Process类应该避免这种错误,也许它应该自动将空输出流和错误流排队,除非用户指示读取它们。一般来说,API的设计应该使做正确的事情更容易,而做错误的事情则很难或不可能

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » Java更多的库谜题82:啤酒爆炸

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情