1. First look at the following code
import java.io.FileInputStream;public class TTT {public static void main(String[] args) throws Exception {for (int i = 0; i < 10; i++) {final String threadId = "thread_" + i;Thread thread = new Thread(new Runnable() {public void run() {System.out.println(threadId + "started!");try {FileInputStream fis = new FileInputStream("/opt/test.log");Thread.sleep(60 * 1000);} catch (Exception ex) {ex.printStackTrace();}System.out.println(threadId + "stopped!");}});thread.start();}Thread.sleep(10 * 60 * 1000);}}2. Compile and run this class on linux, and then use the linux command /usr/sbin/lsof -p <pid> to view the file information opened by this program.
$ /usr/sbin/lsof -p `ps -ef | grep java | grep TTT | awk '{print $2}'` | grep "test.log"java 21562 fkong 3r REG 253,0 0 35471424 /opt/test.logjava 21562 fkong 4r REG 253,0 0 35471424 /opt/test.logjava 21562 fkong 5r REG 253,0 0 35471424 /opt/test.logjava 21562 fkong 6r REG 253,0 0 35471424 /opt/test.logjava 21562 fkong 7r REG 253,0 0 35471424 /opt/test.logjava 21562 fkong 8r REG 253,0 0 35471424 /opt/test.logjava 21562 fkong 11r REG 253,0 0 35471424 /opt/test.logjava 21562 fkong 11r REG 253,0 0 35471424 /opt/test.logjava 21562 fkong 11r REG 253,0 0 35471424 /opt/test.logjava 21562 fkong 12r REG 253,0 0 35471424 /opt/test.logWhether it is during or after 10 threads running, the results of viewing using the lsof command are the same. You can see that 10 file streams are not closed.
3. I have made some changes to this code below, that is, after the thread is executed, all threads are set to null, as follows
import java.io.FileInputStream;import java.util.ArrayList;import java.util.List;public class TTT {public static void main(String[] args) throws Exception {List<Thread> threads = new ArrayList<Thread>();for (int i = 0; i < 10; i++) {final String threadId = "thread_" + i;Thread thread = new Thread(new Runnable() {public void run() {System.out.println(threadId + "started!");try {FileInputStream fis = new FileInputStream("/opt/test.log");Thread.sleep(60 * 1000);} catch (Exception ex) {ex.printStackTrace();}System.out.println(threadId + "stopped!");}});thread.start();threads.add(thread);}Thread.sleep(2 * 60 * 1000);for (Thread thread : threads) {thread = null;}System.out.println("Clean up threads!");Thread.sleep(10 * 60 * 1000);}} Again, use lsof to view during and after the 10 threads are run, and the results are still similar, and there are still 10 file streams that are not closed.
I made some changes again, after setting all threads to null, add (or urge the JVM) to do a few gc operations, as follows:
import java.io.FileInputStream;import java.util.ArrayList;import java.util.List;public class TTT {public static void main(String[] args) throws Exception {List<Thread> threads = new ArrayList<Thread>();for (int i = 0; i < 10; i++) {final String threadId = "thread_" + i;Thread thread = new Thread(new Runnable() {public void run() {System.out.println(threadId + "started!");try {FileInputStream fis = new FileInputStream("/opt/test.log");Thread.sleep(60 * 1000);} catch (Exception ex) {ex.printStackTrace();}System.out.println(threadId + "stopped!");}});thread.start();threads.add(thread);}Thread.sleep(2 * 60 * 1000);for (Thread thread : threads) {thread = null;}System.out.println("Clean up threads!");System.gc();System.gc();System.gc();System.out.println("Finished GC!");Thread.sleep(10 * 60 * 1000);}}Use lsof to view again, and you can still see that 10 file streams are open during running, but after "Finished GC!", the result is that the 10 file streams are closed.
Finally, I simply deleted the statements that set thread to null, and the results of the run are also consistent with the results of performing gc operations above.
In the end, for those IO file streams that are open and not closed in the JVM will recycle them all when they are no longer used when they are doing Full GC next time, but it is still not good to let the JVM do these things. The same old saying is to do your own things.