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

41 篇文章 7 订阅
23 篇文章 2 订阅

具体问题

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;
        } 
    
    • 能够单方向得关闭流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值