题目
一个文件中有10000个数,用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。
- 要求启动10个线程,两两一组,分为5组。
- 每组两个线程分别将文件中的奇数和偶数输出到该组对应的一个文件中,需要偶数线程每打印10个偶数以后,就将奇数线程打印10个奇数,如此交替进行。
- 同时需要记录输出进度,每完成1000个数就在控制台中打印当前完成数量,并在所有线程结束后,在控制台打印”Done”。
题解(带注释)
package com.cielo.wangyi2015;
import java.io.*;
import java.util.Random;
/**
* Created by 63289 on 2017/4/2.
*/
class ThreadGroup implements Runnable{
//所有thread共享同一个单例计数器,记录输出总数
private static Integer count=new Integer(0);
//用于输出
private PrintWriter printWriter;
//轮到奇数线程则为true,偶数线程为false
private boolean isOdd;
//输入的转换成数组的长度2000的文件
private int[] rec;
//记录奇数光标位置
private int oddPosition=0;
//记录偶数光标位置
private int evenPosition=0;
//构造器
public ThreadGroup(PrintWriter printWriter, int[] rec){
this.printWriter=printWriter;
this.rec=rec;
isOdd=false;
}
//管理计数器和输出
private void increaseCountAndPrintInfo(){
synchronized (count){
++count;
if(count%1000==0){
System.out.println("当前完成数量:"+count);
if(count==10000){
System.out.println("Done!");
}
}
}
}
//打印方法
private synchronized boolean print() {
int i = 0;
//打印10个数后交替
while (i < 10) {
//如果奇数和偶数都输出完毕,则停止并等待线程自动退出。
if (oddPosition >= rec.length && evenPosition >= rec.length) {
notifyAll();
return false;
}
//如果输出到最后一个,则直接跳到输出部分
if ((oddPosition >= rec.length && isOdd) || (evenPosition >= rec.length && !isOdd)) {
break;
}
//如果轮到奇数线程
if (isOdd) {
//如果是奇数
if (rec[oddPosition] % 2 == 1) {
//统计本轮输出了多少数
++i;
//输出
printWriter.print(rec[oddPosition] + " ");
printWriter.flush();
//控制台输出
increaseCountAndPrintInfo();
}
//无论是不是奇数奇数光标都要移动
++oddPosition;
//偶数部分和奇数类似,略
} else {
if (rec[evenPosition] % 2 == 0) {
++i;
printWriter.print(rec[evenPosition] + " ");
printWriter.flush();
increaseCountAndPrintInfo();
}
++evenPosition;
}
}
//从奇数线程轮到偶数线程
isOdd=!isOdd;
//通知wait()状态的另一个线程
notifyAll();
try {
//自己进入wait()状态
wait();
}catch (Exception e){
e.printStackTrace();
}
//打印未结束
return true;
}
@Override
public void run(){
//循环打印
while (print()){
}
}
}
public class PrintByThread {
//生成一个随机的10000数字文件,解释略
private static boolean setUpFile(){
try{
PrintWriter printWriter=new PrintWriter(new FileWriter(new File("input.txt"),true));
Random random=new Random();
for(int i=0;i<10000;++i){
printWriter.print(Math.abs(random.nextInt()%100)+" ");
}
printWriter.flush();
printWriter.close();
return true;
}catch (IOException e){
e.printStackTrace();
return false;
}
}
public static void main(String[] args){
try {
//如果生成文件成功
if(setUpFile()){
//读取并转换为String数组
BufferedReader reader=new BufferedReader(new FileReader("input.txt"));
String str=reader.readLine();
reader.close();
String[] strs=str.split(" ");
//分5组把String数组转换成int数组发给线程
int j=0;
for(int i=0;i<5;++i){
int[] rec=new int[2000];
for(int k=0;k<2000;++k){
rec[k]=Integer.parseInt(strs[j]);
++j;
}
PrintWriter printWriter=new PrintWriter(new FileWriter(new File("output"+i+".txt")),true);
ThreadGroup threadGroup=new ThreadGroup(printWriter,rec);
//开启两个同组线程
new Thread(threadGroup).start();
new Thread(threadGroup).start();
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}