最近被问到Log4j如何通过多个线程向一个文件中写入数据,当时没有一点头绪, 因为用过windows记事本的小伙伴都知道,当一个记事本文件被同时打开多次,并且每个都修改,那么只会保留第一次打开的内容,这就是互斥锁的机制吧。
具体场景:三个线程分别读取三个文件a,b,c 并向d文件中写入
现在想起来两个方案给小伙伴分享一下:
第一种(不可行)使用IO流复用,就是多个线程共用一个IO流
出现问题:
1.部分文件内容无法保存。
2.影响其它线程使用文件
第二种方案:
思路:既然不能同时读写,那么就一个或多个线程读取文件,然后单独的一个或多个线程写文件。
比如 创建三个线程r1,r2,r3分别读取a,b,c 创建一个线程w1将内容写入到 d. 那么读写操作就可以同步进行,也不需要IO复用了,只需要创建一个缓冲区即可。
不多说了,上代码(因为需要代码尽量清晰,省略所有io.close())
-
/**
-
* 从abc三个文件中向d中写
-
* 多个线程向内存数组中读,读完之后,由单独的一个线程写入到文件中
-
*/
-
public
class Main042{
-
//创建堵塞队列,用于读线程的数据存放
-
public
static BlockingQueue<
byte[]> queue =
new ArrayBlockingQueue<>(
1024*
1024);
-
//创建 CountDownLatch,标记读线程的状态(是否读取完成)。
-
public
static CountDownLatch count =
new CountDownLatch(
3);
-
public static void main(String[] args){
-
Read r1=
new Read(
"d:/a.txt",queue,count);
-
Read r2=
new Read(
"d:/b.txt",queue,count);
-
Read r3=
new Read(
"d:/c.txt",queue,count);
-
Write w1 =
new Write(
"d:/d.txt", queue, count);
-
r1.start();
-
r2.start();
-
r3.start();
-
w1.start();
-
}
-
-
}
-
-
class Write extends Thread{
-
private BlockingQueue<
byte[]> buffer;
-
private FileOutputStream fileOutputStream;
-
private CountDownLatch count;
-
public Write(String file,BlockingQueue<byte[]> buffer,CountDownLatch count) {
-
this.buffer = buffer;
-
this.count =count;
-
try {
-
this.fileOutputStream =
new FileOutputStream(file);
-
}
catch (FileNotFoundException e) {
-
e.printStackTrace();
-
}
-
}
-
public void run(){
-
boolean b =
true;
-
while(b) {
-
try {
-
fileOutputStream.write(buffer.take());
-
}
catch (Exception e) {
-
e.printStackTrace();
-
}
-
if(buffer.isEmpty()&&count.getCount()==
0) {
-
//当缓冲区没有元素,并且 count为0,则说明读写完成
-
b =
false;
-
}
-
}
-
-
}
-
}
-
//读线程
-
class Read extends Thread{
-
private BlockingQueue<
byte[]> buffer;
-
private FileInputStream fileInputStream;
-
private CountDownLatch count;
-
private
volatile
int i=
0;
-
-
public Read(String readFileName, BlockingQueue<byte[]> buffer,CountDownLatch count) {
-
this.count = count;
-
this.buffer = buffer;
-
try {
-
this.fileInputStream =
new FileInputStream(readFileName);
-
}
catch (FileNotFoundException e) {
-
e.printStackTrace();
-
}
-
}
-
public void run(){
-
try {
-
byte[] b =
new
byte[
1024*
10];
-
while((i = fileInputStream.read(b))>=
0) {
-
buffer.put(Arrays.copyOf(b, i));
-
}
-
}
catch (Exception e) {
-
e.printStackTrace();
-
}
finally {
-
count.countDown();
//读线程结束,count--;
-
}
-
}
-
}
-
-
-