- 使用线程安全的I/O类
- 思路:Java提供了一些线程安全的I/O类,例如
RandomAccessFile
在多线程环境下相对安全。它可以通过文件指针来随机访问文件,在一定程度上减少资源竞争。
- 代码示例:
import java.io.IOException;
import java.io.RandomAccessFile;
public class ThreadSafeFileAccess {
private static final String FILE_NAME = "test.txt";
public static void main(String[] args) {
Thread writerThread = new Thread(() -> {
try (RandomAccessFile raf = new RandomAccessFile(FILE_NAME, "rw")) {
raf.seek(0);
raf.writeUTF("Some data written by writer thread");
} catch (IOException e) {
e.printStackTrace();
}
});
Thread readerThread = new Thread(() -> {
try (RandomAccessFile raf = new RandomAccessFile(FILE_NAME, "r")) {
raf.seek(0);
String data = raf.readUTF();
System.out.println("Data read by reader thread: " + data);
} catch (IOException e) {
e.printStackTrace();
}
});
writerThread.start();
readerThread.start();
try {
writerThread.join();
readerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 使用同步块或锁
- 思路:对文件的读写操作使用
synchronized
关键字或者Lock
接口来同步,确保同一时间只有一个线程可以访问文件。
- 代码示例:
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class SynchronizedFileAccess {
private static final String FILE_NAME = "test.txt";
private static final Object lock = new Object();
public static void main(String[] args) {
Thread writerThread = new Thread(() -> {
synchronized (lock) {
try (PrintWriter out = new PrintWriter(new FileWriter(FILE_NAME, true))) {
out.println("Data written by writer thread");
} catch (IOException e) {
e.printStackTrace();
}
}
});
Thread readerThread = new Thread(() -> {
synchronized (lock) {
try (java.io.BufferedReader in = new java.io.BufferedReader(new java.io.FileReader(FILE_NAME))) {
String line;
while ((line = in.readLine()) != null) {
System.out.println("Data read by reader thread: " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
writerThread.start();
readerThread.start();
try {
writerThread.join();
readerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 使用
FileChannel
和ByteBuffer
- 思路:
FileChannel
提供了更细粒度的控制和更好的性能,并且ByteBuffer
可以提高数据读写的效率。通过使用FileChannel
的lock
方法可以实现文件锁机制,避免资源竞争。
- 代码示例:
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class FileChannelAndByteBufferExample {
private static final String FILE_NAME = "test.txt";
public static void main(String[] args) {
Thread writerThread = new Thread(() -> {
try (FileOutputStream fos = new FileOutputStream(FILE_NAME);
FileChannel channel = fos.getChannel()) {
FileChannel lock = channel.lock();
ByteBuffer buffer = ByteBuffer.wrap("Data written by writer thread".getBytes());
channel.write(buffer);
lock.release();
} catch (IOException e) {
e.printStackTrace();
}
});
Thread readerThread = new Thread(() -> {
try (java.io.FileInputStream fis = new java.io.FileInputStream(FILE_NAME);
FileChannel channel = fis.getChannel()) {
FileChannel lock = channel.lock();
ByteBuffer buffer = ByteBuffer.allocate((int) channel.size());
channel.read(buffer);
buffer.flip();
byte[] data = new byte[buffer.limit()];
buffer.get(data);
System.out.println("Data read by reader thread: " + new String(data));
lock.release();
} catch (IOException e) {
e.printStackTrace();
}
});
writerThread.start();
readerThread.start();
try {
writerThread.join();
readerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 使用线程池和队列
- 思路:将文件读写任务提交到线程池,并通过队列来缓冲任务,避免多个线程直接竞争文件资源。这样可以更好地控制并发度,提高程序的稳定性和效率。
- 代码示例:
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolAndQueueExample {
private static final String FILE_NAME = "test.txt";
private static final BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // corePoolSize
4, // maximumPoolSize
10, TimeUnit.SECONDS,
taskQueue
);
public static void main(String[] args) {
Runnable writeTask = () -> {
try (PrintWriter out = new PrintWriter(new FileWriter(FILE_NAME, true))) {
out.println("Data written by task in thread pool");
} catch (IOException e) {
e.printStackTrace();
}
};
executor.submit(writeTask);
executor.submit(writeTask);
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("Pool did not terminate");
}
}
} catch (InterruptedException ie) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}