需求:一生產者線程讀取指定文件,多個消費者線程將讀取的文件寫入到指定文件中,確保生產者產生的文件大小和消費者寫入完畢的文件大小一致。
思路:
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文件做過測試,消費者數據被完整的複製到指定位置。