IOexception – 读取结束死机 – 在此示例中导致它的原因以及如何修复它 – Java中的multithreading应用程序

这是我在这里发布的问题的扩展 ,虽然这似乎解决了我的问题的一部分,现在我看到IO-Exception read end dead exception 。 我使用的是multithreaded应用程序,其中thread-1 produces随机数,而其他thread-2 consumes它来计算平均值。 一旦平均值达到阈值,我发信号通知thread-1停止产生数字。 这是代码的基本设计。

我收到IO-Exception read end dead exception 。 我想知道为什么会这样,以及如何解决它。 谢谢。

代码如下:

 import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; // class NumGen extends Thread { PipedOutputStream pos; DataOutputStream dos; AtomicBoolean isDone; public NumGen(PipedOutputStream pos,AtomicBoolean isDone){ this.pos=pos; dos=new DataOutputStream(pos); this.isDone=isDone; } public void run(){ while (!isDone.get()){ Random rand = new Random(); try { dos.writeDouble(rand.nextDouble()+100.0); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } class RunningAvg extends Thread { PipedInputStream pis; DataInputStream dis; Double avg; int count; Double runningTotal; AtomicBoolean isDone; public RunningAvg(PipedInputStream pis,AtomicBoolean isDone){ this.pis=pis; dis=new DataInputStream(pis); runningTotal=0.0; avg=0.0; this.isDone=isDone; } public void run(){ try { while (dis.available()>0){ count+=1; runningTotal+=dis.readDouble(); avg=runningTotal/count; System.out.printf("The average in count no : %s is %s%n",count,avg); if (avg>1E5) isDone.set(true); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public class InterThreadComm { public static void main(String[] args){ try { PipedOutputStream pos= new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(pos); AtomicBoolean isDone = new AtomicBoolean(false); NumGen ng = new NumGen(pos,isDone); RunningAvg ra = new RunningAvg(pis,isDone); ng.start(); ra.start(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 

编辑:根据以下答案:我尝试使用try-with-resources关闭Streams。 但我得到java.io.IOException: Pipe closed

 public class InterThreadComm { public static void main(String[] args){ try(PipedOutputStream pos= new PipedOutputStream();PipedInputStream pis =new PipedInputStream(pos)){ AtomicBoolean isDone = new AtomicBoolean(false); NumGen ng = new NumGen(pos,isDone); RunningAvg ra = new RunningAvg(pis,isDone); ng.start(); ra.start(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 

根本原因在于:

 while (dis.available()>0){ 

发生的事情是消费者线程有时会消耗所有数据。 什么都没有,所以它早点破了。

抛出exception是因为PipedInputStream / PipedOutputStream会跟踪正在读取和写入的线程。 有一个名为checkStateForReceive的私有方法抛出,基本上它抱怨你的消费者线程已经结束:

 } else if (readSide != null && !readSide.isAlive()) { throw new IOException("Read end dead"); } 

readSide是消费者线程。)

您可以在堆栈跟踪中看到此调用:

 java.io.IOException:读取结束死亡
     at java.io.PipedInputStream.checkStateForReceive(PipedInputStream.java:246)
    在java.io.PipedInputStream.receive(PipedInputStream.java:210)
     at java.io.PipedOutputStream.write(PipedOutputStream.java:132)
     at java.io.DataOutputStream.writeLong(DataOutputStream.java:207)
     at java.io.DataOutputStream.writeDouble(DataOutputStream.java:242)

因此, write调用receieve输入流,调用checkStateForReceieve并在读取Thread未处于活动状态时抛出。

我认为你的循环条件应该是:

 while(!isDone.get()) { 

与exception无关,我也认为你可能在这里有一个无限循环:

 if (avg>1E5) isDone.set(true); 

您的数字生成器生成100到101之间的数字,因此它们的平均值绝不会大于1e5。 您可能打算检查runningTotal > 1E5

也:

  • 完成后,不要忘记关闭你的溪流。
  • 您的消费者线程在其循环之外捕获IOException,但生产者捕获循环内部。 如果有例外,生产者不会中止:它只是继续前进,一遍又一遍地捕获exception。 您可能希望将catch移动到循环外部,就像使用者一样。

关于您的编辑:

如果要关闭main中的流,可以join线程。

 try( PipedOutputStream pos= new PipedOutputStream(); PipedInputStream pis =new PipedInputStream(pos) ){ AtomicBoolean isDone = new AtomicBoolean(false); NumGen ng = new NumGen(pos,isDone); RunningAvg ra = new RunningAvg(pis,isDone); ng.start(); ra.start(); try { ng.join(); // wait for ng and ra to complete ra.join(); // } catch(InterruptedException ie) {} } catch (IOException e) { e.printStackTrace(); }