Why doesn't more Java code use PipedInputStream / PipedOutputStream?

前端 未结 9 2116
感动是毒
感动是毒 2020-12-02 12:56

I\'ve discovered this idiom recently, and I am wondering if there is something I am missing. I\'ve never seen it used. Nearly all Java code I\'ve worked with in the wild fav

相关标签:
9条回答
  • 2020-12-02 13:43

    java.io pipes have too much context switching (per byte read/write) and their java.nio counterpart requires you to have some NIO background and proper usage of channels and stuff, this is my own implementation of pipes using a blocking queue which for a single producer/consumer will perform fast and scale well:

    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.concurrent.*;
    
    public class QueueOutputStream extends OutputStream
    {
      private static final int DEFAULT_BUFFER_SIZE=1024;
      private static final byte[] END_SIGNAL=new byte[]{};
    
      private final BlockingQueue<byte[]> queue=new LinkedBlockingDeque<>();
      private final byte[] buffer;
    
      private boolean closed=false;
      private int count=0;
    
      public QueueOutputStream()
      {
        this(DEFAULT_BUFFER_SIZE);
      }
    
      public QueueOutputStream(final int bufferSize)
      {
        if(bufferSize<=0){
          throw new IllegalArgumentException("Buffer size <= 0");
        }
        this.buffer=new byte[bufferSize];
      }
    
      private synchronized void flushBuffer()
      {
        if(count>0){
          final byte[] copy=new byte[count];
          System.arraycopy(buffer,0,copy,0,count);
          queue.offer(copy);
          count=0;
        }
      }
    
      @Override
      public synchronized void write(final int b) throws IOException
      {
        if(closed){
          throw new IllegalStateException("Stream is closed");
        }
        if(count>=buffer.length){
          flushBuffer();
        }
        buffer[count++]=(byte)b;
      }
    
      @Override
      public synchronized void write(final byte[] b, final int off, final int len) throws IOException
      {
        super.write(b,off,len);
      }
    
      @Override
      public synchronized void close() throws IOException
      {
        flushBuffer();
        queue.offer(END_SIGNAL);
        closed=true;
      }
    
      public Future<Void> asyncSendToOutputStream(final ExecutorService executor, final OutputStream outputStream)
      {
        return executor.submit(
                new Callable<Void>()
                {
                  @Override
                  public Void call() throws Exception
                  {
                    try{
                      byte[] buffer=queue.take();
                      while(buffer!=END_SIGNAL){
                        outputStream.write(buffer);
                        buffer=queue.take();
                      }
                      outputStream.flush();
                    } catch(Exception e){
                      close();
                      throw e;
                    } finally{
                      outputStream.close();
                    }
                    return null;
                  }
                }
        );
      }
    
    0 讨论(0)
  • 2020-12-02 13:44

    I tried using these classes a while back for something, I forget the details. But I did discover that their implementation is fatally flawed. I can't remember what it was but I have a sneaky memory that it may have been a race condition which meant that they occasionally deadlocked (And yes, of course I was using them in separately threads: they simply aren't usable in a single thread and weren't designed to be).

    I might have a look at their source code andsee if I can see what the problem might have been.

    0 讨论(0)
  • 2020-12-02 13:48

    PipedInputStream and PipeOutputStream will sleep its thread for 1 second whenever they are blocking waiting for the other side to read or write out of the full or empty buffer. Do not use.

    0 讨论(0)
提交回复
热议问题