Overview
Java程序中的常见的资源有:文件,Socket,数据库连接。在使用这些资源时候要分外小心,因为操作系统可同时操作的资源是有限的,比如默认情况下系统允许同时打开的文件数为1024个,Mysql服务器默认允许的最大连接数是100,所以操作这些资源时候要注意即使在遇到错误时也要让系统能正确回收资源。如果发生错误时候,打开的文件描述符没关闭或数据库连接没关闭,积累到一定程度后,应用将会变得不可用,只能重启。
try-catch-finally
Java提供了try-catch-finally来保证程序遇到异常时总是有机会可以处理资源的关闭 – 调用资源对象的close()方法。但经验不足的Java程序员还是会错误的管理资源,而造成资源的泄露,静态代码分析工具,如FindBugs可以帮助发现此类问题。
首先我们来看一段文件操作代码:
private void copy(String from, String to) throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
in = new FileInputStream(from);
out = new FileOutputStream(to);
int c;
while ((c = in.read()) != -1)
out.write(c);
in.close();
out.close();
}
一眼看上去,代码挺整齐的,逻辑也容易理解。但其中有一个很大的问题是,如果out.write调用失败(比如磁盘空间满了)方法异常退出,in.close()和out.close()就不会被调用,而in和out对象内部都引用了系统资源-文件描述符,这样会导致文件描述符没有关闭,不能被重新使用而直到整个Java进程退出。
File descriptor
Linux的每个进程(如:Java进程)都有一个文件描述符表管理当前进程访问的所有的文件,文件描述符关联了系统文件表中的file entry,系统能容纳多少file entry是有限制的,如果超过限制系统会拒绝访问,抛出Too many opened files错误。

较为正确的代码应该是:
private void copy(String src, String dest) throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream(src);
out = new FileOutputStream(dest);
int c;
while ((c = in.read()) != -1)
out.write(c);
} finally {
try {
if (in!=null) {
in.close();
}
} finally {
if (out!=null) {
out.close();
}
}
}
}
但是这样的代码写起来是不是让人有点沮丧?这样写代码犯错的可能性确实比较大。 改良过后的代码阅读性好一些:
[Read More]