src/share/classes/java/io/FileOutputStream.java

Print this page

        

*** 67,77 **** --- 67,86 ---- */ private FileChannel channel; private final Object closeLock = new Object(); private volatile boolean closed = false; + private static final ThreadLocal<Boolean> runningFinalize = + new ThreadLocal<>(); + private static boolean isRunningFinalize() { + Boolean val; + if ((val = runningFinalize.get()) != null) + return val.booleanValue(); + return false; + } + /** * Creates a file output stream to write to the file with the * specified name. A new <code>FileDescriptor</code> object is * created to represent this file connection. * <p>
*** 197,207 **** throw new NullPointerException(); } this.fd = new FileDescriptor(); this.append = append; ! fd.attach(this); open(name, append); } /** * Creates a file output stream to write to the specified file --- 206,216 ---- throw new NullPointerException(); } this.fd = new FileDescriptor(); this.append = append; ! fd.incrementAndGetUseCount(); open(name, append); } /** * Creates a file output stream to write to the specified file
*** 234,244 **** if (security != null) { security.checkWrite(fdObj); } this.fd = fdObj; this.append = false; ! fd.attach(this); } /** * Opens a file, with the specified name, for overwriting or appending. * @param name name of file to be opened --- 243,259 ---- if (security != null) { security.checkWrite(fdObj); } this.fd = fdObj; this.append = false; ! ! /* ! * FileDescriptor is being shared by streams. ! * Ensure that it's GC'ed only when all the streams/channels are done ! * using it. ! */ ! fd.incrementAndGetUseCount(); } /** * Opens a file, with the specified name, for overwriting or appending. * @param name name of file to be opened
*** 323,339 **** } closed = true; } if (channel != null) { channel.close(); } ! fd.closeAll(new Closeable() { ! public void close() throws IOException { close0(); } - }); } /** * Returns the file descriptor associated with this stream. * --- 338,368 ---- } closed = true; } if (channel != null) { + /* + * Decrement FD use count associated with the channel + * The use count is incremented whenever a new channel + * is obtained from this stream. + */ + fd.decrementAndGetUseCount(); channel.close(); } ! ! /* ! * Decrement FD use count associated with this stream ! */ ! int useCount = fd.decrementAndGetUseCount(); ! ! /* ! * If FileDescriptor is still in use by another stream, the finalizer ! * will not close it. ! */ ! if ((useCount <= 0) || !isRunningFinalize()) { close0(); } } /** * Returns the file descriptor associated with this stream. *
*** 343,355 **** * * @exception IOException if an I/O error occurs. * @see java.io.FileDescriptor */ public final FileDescriptor getFD() throws IOException { ! if (fd != null) { ! return fd; ! } throw new IOException(); } /** * Returns the unique {@link java.nio.channels.FileChannel FileChannel} --- 372,382 ---- * * @exception IOException if an I/O error occurs. * @see java.io.FileDescriptor */ public final FileDescriptor getFD() throws IOException { ! if (fd != null) return fd; throw new IOException(); } /** * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
*** 370,379 **** --- 397,413 ---- */ public FileChannel getChannel() { synchronized (this) { if (channel == null) { channel = FileChannelImpl.open(fd, false, true, append, this); + + /* + * Increment fd's use count. Invoking the channel's close() + * method will result in decrementing the use count set for + * the channel. + */ + fd.incrementAndGetUseCount(); } return channel; } }
*** 388,405 **** protected void finalize() throws IOException { if (fd != null) { if (fd == FileDescriptor.out || fd == FileDescriptor.err) { flush(); } else { ! /* if fd is shared, the references in FileDescriptor ! * will ensure that finalizer is only called when ! * safe to do so. All references using the fd have ! * become unreachable. We can call close() */ close(); } } } private native void close0() throws IOException; private static native void initIDs(); --- 422,445 ---- protected void finalize() throws IOException { if (fd != null) { if (fd == FileDescriptor.out || fd == FileDescriptor.err) { flush(); } else { ! ! /* ! * Finalizer should not release the FileDescriptor if another ! * stream is still using it. If the user directly invokes ! * close() then the FileDescriptor is also released. */ + runningFinalize.set(Boolean.TRUE); + try { close(); + } finally { + runningFinalize.set(Boolean.FALSE); } } + } } private native void close0() throws IOException; private static native void initIDs();