【java_基础深入】源码分析 BufferedOutputStream.close() flush() Socket.shutdownOutput()

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/chenghan_yang/article/details/101082377

具体问题

bos.未flush() 会造成 Socket 的 阻塞
解决办法: 用 flush 或者 Socket.shutdownOutput()

BufferedOutputStream.close() flush() 和 Socket.shutdownOutput

BufferedOuputStream 成员变量 和 flush()

  • BufferedOutputStream 内层被包装类 FilterOutputStream

    /**
     * BufferedOutputStream 继承至 FilterOutputStream
     * 
     */
    public class BufferedOutputStream extends FilterOutputStream {}
    
    public class FilterOutputStream extends OutputStream {
        // 最底层的被包装类 OutputStream
         protected OutputStream out;
        
    }
    

    BufferedOutputStreamout 成员变量指的就是被FilterOutputStream包装的 OutputStream

  • 构造方法

    public class BufferedOutputStream extends FilterOutputStream {
    	// 接收一个 OutputStream 及其子类 传递给带双参的构造函数
        public BufferedOutputStream(OutputStream out) {
            	// 不指定 buffered 的大小则默认为8192字节
                this(out, 8192);
        }
    
    	// 带双参构造函数, 调用父类的
        public BufferedOutputStream(OutputStream out, int size) {
            super(out);
            if (size <= 0) {
                throw new IllegalArgumentException("Buffer size <= 0");
            }
            buf = new byte[size];
        }
    }
    
    • BufferedOuputStream.flush()

          @Override
          public synchronized void flush() throws IOException {
              flushBuffer();
              out.flush();
          }
      
      • **flush()**调用本类的 **flushBuffer() **+ out.flush()

            /** Flush the internal buffer */
            private void flushBuffer() throws IOException {
                if (count > 0) {
                    out.write(buf, 0, count);
                    count = 0;
                }
            }
        
  • write(byte b[], int off, int len)) 方法

        /**
         * 内置的 buffered 桶, 用于装数据
         */
        protected byte buf[];
    
    	/**
         * @param out 内部包装的 OutputStream
         */
        public BufferedOutputStream(OutputStream out) {
            this(out, 8192);
        }
    
    @Override
        public synchronized void write(byte b[], int off, int len) throws IOException {
            // 第一次装的数据已经满了, 清空buffer的数据再用out去写
            if (len >= buf.length) {
                flushBuffer();
                out.write(b, off, len);
                return;
            }
            // 只有 buffered 装满了,才清空 buffer 的数据
            if (len > buf.length - count) {
                flushBuffer();
            }
            // 否则先将数据写入buf内,等待下次写数据
            System.arraycopy(b, off, buf, count, len);
            count += len;
        }
    

    综上 : BufferedOutputStream 是 FilterOutputStream 的包装类,

    ​ FilterOutputStream 是 OutputStream 的包装类


BufferedOutputStream .close() 和 Socket.shutdownOutput()

  • BufferedOutputStream.close() 源码

        @Override
        public void close() throws IOException {
            if (closed) {
                return;
            }
            closed = true;
    
            Throwable flushException = null;
            try {
                flush();
            } catch (Throwable e) {
                flushException = e;
                throw e;
            } finally {
                if (flushException == null) {
                    out.close();
                } else {
                    try {
                        out.close();
                        ...
                    }
                }
            }
        }
    

    BufferedOutputStream 内部调用了底层包装类 OuptStream.close()

  • JDK8及之前释放资源使用 close() – 不安全

        /**
         *  关闭流直接关闭socket
         */
    	public void close() throws IOException {
            // Prevent recursion. See BugId 4484411
            if (closing)
                return;
            closing = true;
            if (socket != null) {
                if (!socket.isClosed())
                    socket.close();
            } else
                impl.close();
            closing = false;
        }
    
  • JDK9新特性:Socket.shutdownOutput()

        public void shutdownOutput() throws IOException
        {
            if (isClosed())
                throw new SocketException("Socket is closed");
            if (!isConnected())
                throw new SocketException("Socket is not connected");
            if (isOutputShutdown())
                throw new SocketException("Socket output is already shutdown");
            getImpl().shutdownOutput();
            shutOut = true;
        } 
    
    • 能够单方向得关闭流

猜你喜欢

转载自blog.csdn.net/chenghan_yang/article/details/101082377