这篇文章使用的思想来源于:“随缘剑客”的一篇文章
题目:
一个文件中有10000个数,用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。要求启动10个线程,两两一组,分为5组。每组两个线程分别将文件中的奇数和偶数输出到该组对应的一个文件中,需要偶数线程每打印10个偶数以后,就将奇数线程打印10个奇数,如此交替进行。同时需要记录输出进度,每完成1000个数就在控制台中打印当前完成数量,并在所有线程结束后,在控制台打印”Done”.
思想大纲:
首先创建存储10000个数的文本文件,把10000个数字取出来放在数组中,然后分为5个文件,每个文件里面放置2000个数字,一个文件下面设置两个线程,一个用于输出偶数,一个用于输出奇数,两个线程中的参数是同一个MyRunnable类,MyRunnable类中的count等于全部线程放入数字的总数目,虽然只有两个线程是同一个MyRunnable,但是count是静态的,无论新建多少个对象,都只有一个count,里面的数值可以改变,但是不能新建count,里面还有一个变量是lock,这个的目的是保证只能有一个线程进行count++以及输出相关文字的,其他的线程只能等待,当进行操作之后,其他的线程再进来也不会在输出相关文字了,里面还有两个参数是EVEN和ODD,这个的目的就是代表属于的是偶数还是奇数,毕竟有两个线程,通过对type的操控,刚开始让type是EVEN,后来放入十个偶数之后把type取反,然后这个时候就可以放入奇数了,然后放入十个奇数之后在把type取反,然后就可以在放入偶数了,循环罔替,PrintWriter writer是让我往哪个文件里面放数字的,int[] records是存有那两千个数的数组,evenPoint和oddPoint分别是偶数点和奇数点的标记,当往文件里面输入偶数或者奇数的时候,无论是不是成功,都需要+1,原因就是让下一次找偶数或者奇数更方便,当成功把偶数或者奇数放置在文件中的时候才进行i++,这样可以保证放置的偶数或者奇数一定是10个,每放置一次数,count就+1,当放置的数目是1000的整数倍,就输出1次,如果输出的是10000,再多输出一个Done!,如果奇数或者偶数输出完了,但是里面没发现奇数或者偶数了,那就退出for循环,即使没有输入10个也是如此,如果全部的数字都输入完了,代表的标志就是偶数或者奇数的数目都达到了2000,然后循环先把之前的等待的线程放了,然后返回false,这个时候while就结束了,标志一个文件里面放置2000个数已经完成了,五次循环之后,五个文件里面都放置了2000个数字;不过需要注意的有三个地方,分别是PrintWriter不能多次利用,每利用一次就需要重新定义一个,不然会出错误,还有一个就是EVEN和ODD只能是0和-1,不然~没用,如果你使用别的方法也可以最后一个就是一定要flush(),并且要及时flush()
代码如下:
public class Test {
public static void main(String[] args) {
PrintWriter printWriter = null;
PrintWriter writer = null;
BufferedReader bufferedReader = null;
try {
printWriter = new PrintWriter("input.txt");
Random random = new Random();
for (int i = 0; i < 10000; i++) {
int nextInt = random.nextInt(1000);
printWriter.print(nextInt + " ");
}
printWriter.flush();
bufferedReader = new BufferedReader(new FileReader("input.txt"));
String s = null;
StringBuilder str = new StringBuilder();
while ((s = bufferedReader.readLine()) != null) {
str.append(s);
}
String[] split = str.toString().split(" ");
int m = 0;
for (int i = 0; i < 5; i++) {
int[] records = new int[2000];
for (int j = 0; j < 2000; j++) {
records[j] = Integer.parseInt(split[m]);
m++;
}
writer = new PrintWriter("output" + i + ".txt");
MyRunnable myRunnable = new MyRunnable(records, writer);
new Thread(myRunnable).start();
new Thread(myRunnable).start();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (printWriter != null) {
printWriter.close();
}
if (writer != null) {
printWriter.close();
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
class MyRunnable implements Runnable {
private static int count = 0;
private static final Object lock = new Object();
private static final int EVEN = 0;
private static final int ODD = -1;
private int type;
private PrintWriter writer;
private int[] records;
private int evenPoint = 0;
private int oddPoint = 0;
public MyRunnable(int[] records, PrintWriter writer) {
this.records = records;
this.writer = writer;
this.type = EVEN;
}
@Override
public void run() {
while (print()) ;
}
private synchronized boolean print() {
for (int i = 0; i < 10; ) {
if (evenPoint >= records.length && oddPoint >= records.length) {
notifyAll();
return false;
}
if ((evenPoint >= records.length && type == EVEN) || (oddPoint >= records.length && type == ODD)) {
break;
}
if (type == EVEN) {
if (records[evenPoint] % 2 == 0) {
i++;
writer.print(records[evenPoint] + " ");
writer.flush();
synchronized (lock) {
count++;
if (count % 1000 == 0) {
System.out.println("已经打印了" + count+"个");
if (count == 10000) {
System.out.println("Done!");
}
}
}
}
evenPoint++;
} else {
if (records[oddPoint] % 2 == 1) {
i++;
writer.print(records[oddPoint] + " ");
writer.flush();
synchronized (lock) {
count++;
if (count % 1000 == 0) {
System.out.println("已经打印了" + count+"个");
if (count == 10000) {
System.out.println("Done!");
}
}
}
}
oddPoint++;
}
}
type = ~type;
notifyAll();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
}
结果:
已经打印了1000个
已经打印了2000个
已经打印了3000个
已经打印了4000个
已经打印了5000个
已经打印了6000个
已经打印了7000个
已经打印了8000个
已经打印了9000个
已经打印了10000个
Done!