需求:一生产者线程读取指定文件,多个消费者线程将读取的文件写入到指定文件中,确保生产者产生的文件大小和消费者写入完毕的文件大小一致。
思路:
1、生产者和消费者读取同一个队列。
2、生产者通过输入流取得文件的字节数组,写入到队列中;消费者读取队列数据,将得到的数据插入到文件底部。
3、使用关键字synchronized对队列加锁,当队列为空时,消费者停止消费,当队列数据长度达到指定容量时,生产者停止生产。
4、生产者文件数据生产完毕后,置全局endFlag=true,消费者取得endFlag后,退出线程,停止程序。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
public class ThreadAction extends Thread {
public static long start = System.currentTimeMillis(); //程序开始时间
private static final int CAPACITY = 5; //队列最大容量
private static boolean endFlag = false; //是否结束标志,true为结束
public static void main(String args[]) {
new File("G:\\IDEA\\destination\\a.txt").delete();//指定的文件存在则删除
Queue<byte[]> queue = new LinkedList<byte[]>();
Thread producer1 = new Producer("P-1", queue, CAPACITY, "G:\\IDEA\\testdata\\");
Thread consumer1 = new Consumer("C1", queue, CAPACITY, "G:\\IDEA\\destination\\a.txt");
Thread consumer2 = new Consumer("C2", queue, CAPACITY, "G:\\IDEA\\destination\\a.txt");
Thread consumer3 = new Consumer("C3", queue, CAPACITY, "G:\\IDEA\\destination\\a.txt");
Thread consumer4 = new Consumer("C4", queue, CAPACITY, "G:\\IDEA\\destination\\a.txt");
Thread consumer5 = new Consumer("C5", queue, CAPACITY, "G:\\IDEA\\destination\\a.txt");
Thread consumer6 = new Consumer("C6", queue, CAPACITY, "G:\\IDEA\\destination\\a.txt");
producer1.start();
consumer1.start();
consumer2.start();
consumer3.start();
consumer4.start();
consumer5.start();
consumer6.start();
}
/**
* 生产者
*/
public static class Producer extends Thread {
private Queue<byte[]> queue;
String name;
int maxSize;
String source;
int size = 1024 * 500;
public Producer(String name, Queue<byte[]> queue, int maxSize, String source) {
super(name);
this.name = name;
this.queue = queue;
this.maxSize = maxSize;
this.source = source;
}
@Override
public void run() {
File f = new File(source);
for (File f0 : f.listFiles()) {
FileInputStream fis = null;
try {
fis = new FileInputStream(f0);//创建输入流对象
int len = 0;
byte datas[] = new byte[size];//创建搬运工具
while ((len = fis.read(datas)) != -1) {
synchronized (queue) {
while (queue.size() == maxSize) {
try {
System.out.println("Queue is full, Producer[" + name + "] thread waiting for " + "consumer to take something from queue.");
queue.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
if (len < size) {
byte databB[] = new byte[len];//创建搬运工具
System.arraycopy(datas, 0, databB, 0, len);
queue.offer(databB);
System.out.println("endFlag++" + endFlag);
queue.notifyAll();
endFlag = true;
break;
}
queue.offer(datas);
queue.notifyAll();
try {
Thread.sleep(new Random().nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 消费者
*/
public static class Consumer extends Thread {
private Queue<byte[]> queue;
String name;
int maxSize;
String destination;
public Consumer(String name, Queue<byte[]> queue, int maxSize, String destination) {
super(name);
this.name = name;
this.queue = queue;
this.maxSize = maxSize;
this.destination = destination;
}
@Override
public void run() {
FileOutputStream fos = null;
try {
//如果文件存在,则追加内容;如果文件不存在,则创建文件
fos = new FileOutputStream(destination, true); //创建输出流对象
} catch (IOException e) {
e.printStackTrace();
}
while (!endFlag) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
System.out.println("Queue is empty, Consumer[" + name + "] thread is waiting for Producer");
queue.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
// System.out.println("消费内容"+new String(queue.peek()));
byte[] x = queue.poll();
System.out.println(Thread.currentThread().getName() + "消费者队列:" + queue.size());
try {
fos.write(x);
} catch (IOException e) {
e.printStackTrace();
}
queue.notifyAll();
try {
Thread.sleep(new Random().nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
long end = System.currentTimeMillis();
System.out.println("耗时" + (end - start));
System.exit(1);
}
}
}
}
程序已使用276MB的txt文件做过测试,消费者数据被完整的复制到指定位置。