src/share/classes/java/io/FileInputStream.java
Print this page
@@ -54,10 +54,20 @@
private FileChannel channel = null;
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 <code>FileInputStream</code> by
* opening a connection to an actual file,
* the file named by the path name <code>name</code>
* in the file system. A new <code>FileDescriptor</code>
@@ -122,11 +132,11 @@
}
if (name == null) {
throw new NullPointerException();
}
fd = new FileDescriptor();
- fd.attach(this);
+ fd.incrementAndGetUseCount();
open(name);
}
/**
* Creates a <code>FileInputStream</code> by using the file descriptor
@@ -162,13 +172,14 @@
}
fd = fdObj;
/*
* FileDescriptor is being shared by streams.
- * Register this stream with FileDescriptor tracker.
+ * Ensure that it's GC'ed only when all the streams/channels are done
+ * using it.
*/
- fd.attach(this);
+ fd.incrementAndGetUseCount();
}
/**
* Opens the specified file for reading.
* @param name the name of the file
@@ -291,17 +302,31 @@
return;
}
closed = true;
}
if (channel != null) {
+ /*
+ * Decrement the 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();
}
- fd.closeAll(new Closeable() {
- public void close() throws IOException {
+
+ /*
+ * Decrement the 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 <code>FileDescriptor</code>
* object that represents the connection to
@@ -311,13 +336,11 @@
* @return the file descriptor object associated with this stream.
* @exception IOException if an I/O error occurs.
* @see java.io.FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
- if (fd != null) {
- return fd;
- }
+ if (fd != null) return fd;
throw new IOException();
}
/**
* Returns the unique {@link java.nio.channels.FileChannel FileChannel}
@@ -337,10 +360,17 @@
*/
public FileChannel getChannel() {
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, true, false, 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;
}
}
@@ -359,14 +389,20 @@
* @exception IOException if an I/O error occurs.
* @see java.io.FileInputStream#close()
*/
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) {
- /* 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()
+
+ /*
+ * 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);
}
}
+ }
}