Java I/O 流在多线程环境中的使用
前言
在多线程环境中使用 Java I/O 流需要特别注意线程安全问题,如果不正确使用,会导致数据损坏或不一致。本文将深入探讨 I/O 流在多线程中的正确用法,并通过实战案例进行演示。
同步
最简单的确保线程安全的方法是同步 I/O 操作。对于涉及同一文件的读写操作,使用以下代码块将其同步:
synchronized (file) {
// 读写操作
}
线程局部变量
另一种方法是使用线程局部变量 (ThreadLocal
),为每个线程提供 I/O 对象的单独副本。这样,每个线程都可以安全地访问自己的 I/O 对象,而不会与其他线程产生冲突:
public class IOUtil {
private static final ThreadLocal<BufferedInputStream> inputStream = new ThreadLocal<>();
public static BufferedInputStream getInputStream(String fileName) {
synchronized (inputStream) {
BufferedInputStream stream = inputStream.get();
if (stream == null) {
stream = new BufferedInputStream(new FileInputStream(fileName));
inputStream.set(stream);
}
return stream;
}
}
}
并发队列
对于需要处理多个 I/O 操作的情况,可以使用并发队列(BlockingQueue
)。每个线程可以将 I/O 操作放入队列中,另一个线程可以从队列中取出并执行这些操作:
public class FileProcessor implements Runnable {
private BlockingQueue<String> fileQueue;
@Override
public void run() {
while (!fileQueue.isEmpty()) {
String fileName = fileQueue.take();
try (BufferedReader in = new BufferedReader(new FileReader(fileName))) {
// 处理文件
} catch (IOException e) {
// 处理异常
}
}
}
}
实战案例
场景:多个线程同时读取同一文件的内容并输出到控制台。
实现:
import java.io.*;
import java.util.concurrent.*;
public class MultiThreadRead {
private static final String FILE_NAME = "test.txt";
private static final int NUM_THREADS = 4;
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
BlockingQueue<String> fileQueue = new ArrayBlockingQueue<>(NUM_THREADS);
try (BufferedReader in = new BufferedReader(new FileReader(FILE_NAME))) {
String line;
while ((line = in.readLine()) != null) {
fileQueue.put(line);
}
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < NUM_THREADS; i++) {
executor.execute(new FileProcessor(fileQueue));
}
executor.shutdown();
}
}