1.先看以下一段代碼
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.在linux上編譯并運行這個類,然后使用linux的命令/usr/sbin/lsof -p <pid>來查看這個程序打開的文件信息
$ /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 9r REG 253,0 0 35471424 /opt/test.logjava 21562 fkong 10r 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.log不管是在10個線程運行過程中還是運行完,使用lsof命令查看的結果都一樣,都可以看到有10個文件流沒有關閉。
3.下面我把這個代碼做了一些改動,就是在線程執行完之后,將所有線程置為null,如下
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); }} 再次在10個線程運行過程中和運行完畢后使用lsof查看,結果仍然類似,還是有10個文件流沒有關閉。
我再次做了一些改動,在將所有線程置為null以后,增加(或者說是催促JVM)做幾次gc操作,如下:
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); }}再次使用lsof查看,在運行中仍然還是可以看到那有10個文件流打開著,但是在“Finished GC!”之后,看到的結果是那10個打開的文件流都被關閉了。
最后,我干脆把那些設置thread為null的語句刪除了,運行的結果也和上面執行gc操作的結果一致。
最終,JVM中對于那些打開了沒有關閉的IO文件流,會在不再被使用的情況下,等到下次做Full GC的時候把他們全部回收,但是讓JVM去干這些事總歸還是不好的,還是那句老話,自己的事情自己做。
新聞熱點
疑難解答