并发IO
有时,你需要并发地处理输入和输出。换句话说,可能需要1个以上的线程处理输入和产生输出。不如,一个应用需要处理磁盘上一大推的文件。这可以由并行完成,具有性能增益。或者你得有个服务器,像一个web服务器或聊天服务器,它接收很多独立的连接和请求。这些也可以用并行处理获得一些增益效果。
如果你需要并发IO,这里有一些普遍的你应该了解情况。
在同一时间,不止有一个线程从InputStream或Reader中读取数据。或在同一时间,不止有一个线程从OutputStream或Writer中写入数据。如果是你,你没有方法确保每个线程将会读取多少输入数据,或线程写入输出流的数据的结果。
如果这些线程有序地使用一个流、reader或writer,你可能有不止一个线程。比如,你有一个线程确保输入中请求的类型,然后把它传递到合适的线程以进一步处理。这样访问流/reader/weriter有可能是有序地。注意,处理线程间的流的代码应该完全同步。
注意:在Java NIO中,你可以用单独的线程向一个“通道”中读取或从中读取写入。比如,你有很多打开的网络连接,但是每一个连接只有很少的数据,比如在一个聊天服务器,你有一个单独的线程监视所以的通道(连接)。Java NIO是一个不同的情况,将涵盖在以后的教程中。
异常处理(Exception Handling)
当你用完流和Readers/Writers时,需要完全关闭他们。调用close()方法就可以完成。这需要一些考虑。看这段代码:
InputStream input = new FileInputStream("c:\\data\\input-text.txt");
int data = input.read();
while(data != -1) {
//do something with data...
doSomethingWithData(data);
data = input.read();
}
input.close();
起初瞥一眼,这段代码看起来没问题。但从内部的doSomethingWithData()方法抛出异常会发生什么?InputStream永远关不掉。
这样重写代码可以避免这种情况:
try{
InputStream input = null;
int data = input.read();
whlie(data != -1){
//do something with data...
doSomethingWithData(da);
data = input.read();
}
}catch(Exception e){
//do something with e... log, perhaps rethrow etc.
}finally{
if(input != null){
input.close();
}
}
看到在一个finally语句中输入流现在是关闭的。不管在try快中发生了什么,finally语句都讲被执行。因此输入流将会永远地关闭。
但是如果close()方法抛出异常将会发生什么?流已经被关闭了?那么,捕捉这样的情况需要把close()方法也包在try-catch块中,像这样:
} finally {
try{
if(input != null) input.close();
} catch(IOException e){
//do something, or ignore.
}
}
代码完全地处理输入流的迭代(或者是输出流),和你看到的一样丑,一旦你也在那儿得到了正确的异常处理。丑陋的异常处理代码特别不好,不得不展开你的代码,一遍一遍的重复。如果匆忙地有人剪去一角,跳过异常处理 ,会怎么样?
再者,想象一下从doSomethingWithData()抛出一个异常。第一个catch分句将捕捉异常,然后finally语句将试着关闭输入流。但是,如果从input.close()方法抛出异常呢?哪一个异常会传到调用栈呢?
幸运的是,这个问题有一个方法。解决方式是调用“Exception Handling Templates”。创建一个异常处理样板,在使用完流后就关闭它们。这个模板一次写完,然后在你的代码中复用。简单又好。学习更多,去Exception Handling Templates in Java.
Java IO Exception Handling From Java 7(Java7中Java IO异常处理)
Java7以后,java中包含了一些新的异常处理机制,叫“try with resources”。这个异常处理机制特别针对当你用完资源需要完全关闭是的异常处理,想输入流和输出流等等。你可以在我的关于Try-with-resources in Java 7教程中获取更多.