1 importjava.io.BufferedReader;2 importjava.io.File;3 importjava.io.FileReader;4 importjava.io.FileWriter;5 importjava.io.PrintWriter;6 importjava.util.Random;7
8 /**
9 * 一个文件中有10000个数,用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。要求启动10个线程,10 * 两两一组11 * ,分为5组。每组两个线程分别将文件中的奇数和偶数输出到该组对应的一个文件中,需要偶数线程每打印10个偶数以后,就将奇数线程打印10个奇数,如此交替进行12 * 。同时需要记录输出进度,每完成1000个数就在控制台中打印当前完成数量,并在所有线程结束后,在控制台打印”Done”.13 *14 *@authorAdministrator15 *16 */
17
18 /**
19 * 分析:可以将10000个数分成5份,每一份(2000个数)对应一组,即两个线程,来分别输出这一份的奇数和偶数,20 * 同时声明一个共享变量,用于统计当前所有线程输出的个数,反映记录的输出进度21 *22 */
23 public classPrintByThread {24 public static voidmain(String[] args) {25 try{26 //生成一个10000个数的文件
27 PrintWriter pw = new PrintWriter(new FileWriter(newFile(28 "input.txt"), true));29 Random random = newRandom();30 for (int i = 0; i < 10000; i++) {31 pw.print(Math.abs(random.nextInt()) % 100 + " ");32 }33 pw.flush();34 pw.close();35
36 //读取文件中的数字,分5次读取,每次读取2000个
37 BufferedReader reader = new BufferedReader(newFileReader(38 "input.txt"));39 String str =reader.readLine();40 reader.close();41 //将一行字符串全部解析为10000个数字
42 String[] strs = str.split(" ");43 //10000个数的索引计数
44 int j = 0;45 for (int i = 0; i < 5; i++) {46 int[] records = new int[2000];47 for (int k = 0; k < 2000; k++) {48 records[k] =Integer.parseInt(strs[j]);49 j++;50 }51 //定义输出文件
52 PrintWriter writer = new PrintWriter(new FileWriter(newFile(53 "output" + i + ".txt")), true);54 //定义实现的方法
55 ThreadGroup group = newThreadGroup(records, writer);56 //开启一队线程
57 newThread(group).start();58 newThread(group).start();59 }60 } catch(Exception e) {61 e.printStackTrace();62 }63 }64 }65
66 class ThreadGroup implementsRunnable {67
68 //所有的ThreadGroup类对象共享一个count变量,用来记录输出的总数
69 private static intcount;70 //所有的ThreadGroup类对象共享一个锁,用于count变量的同步,任何一个线程需要修改count变量,必须取得该锁
71 private static Object lock = newObject();72 //用0代表偶数
73 public static final int EVEN = 0;74 //-1代表奇数
75 public static final int ODD = -1;76
77 //*********以上静态变量,属于整个类所有***********
78 private inttype;79 private int[] records;80 private PrintWriter writer;//每组共享一个writer,输出到同一个文件
81 private int oddPoint = 0;//记录每次打印奇数的起始位置
82 private int evenPoint = 0;//记录每次打印偶数的起始位置
83
84 public ThreadGroup(int[] records, PrintWriter writer) {85 this.records =records;86 this.writer =writer;87 this.type =EVEN;88 }89
90 //线程实现方法
91 @Override92 public voidrun() {93 while(print())94 ;95 }96
97 private synchronized booleanprint() {98 for (int i = 0; i < 10;) {99 //如果奇数和偶数都打印完成以后,就直接停止打印循环,等待该线程自己结束
100 if (oddPoint >= records.length && evenPoint >=records.length) {101 notifyAll();102 return false;103 }104
105 //如果该线程该打印奇数,但奇数已经打印晚了,就直接停止本次10个数的打印,106 //同理偶数,等下次切换打印类型后,再开始打印另外一种类型
107 if ((oddPoint >= records.length && type ==ODD)108 || (evenPoint >= records.length && type ==EVEN)) {109 break;110 }111
112 //判断开始打印偶数
113 if (type ==EVEN) {114 if (records[evenPoint] % 2 == 0) {115 i++;116 writer.print(records[evenPoint] + " ");117 writer.flush();118 //锁定全局变量方便线程输出后计数
119 synchronized(lock) {120 count++;121 if (count % 1000 == 0) {122 System.out.println("当前完成数量:" +count);123 if (count == 10000) {124 System.out.println("Done!");125 }126 }127 }128 }129 //无论是否是偶数,打印成功一个后,偶数的起始位置都要后移
130 evenPoint++;131 } else{132 //打印奇数
133 if (records[oddPoint] % 2 == 1) {134 i++;135 writer.print(records[oddPoint] + " ");136 writer.flush();137 //锁定全局变量方便线程输出后计数
138 synchronized(lock) {139 count++;140 if (count % 1000 == 0) {141 System.out.println("当前完成数量:" +count);142 if (count == 10000) {143 System.out.println("Done!");144 }145 }146 }147 }148 //无论是否是奇数,打印成功一个后,偶数的起始位置都要后移
149 oddPoint++;150 }151 }152 //切换打印类型
153 type = ~type;154 //一组中的任一线程打印完后唤醒另一个线程
155 notifyAll();156 try{157 //释放锁进入等待状态,等待另一线程打印
158 wait();159 } catch(Exception e) {160 e.printStackTrace();161 }162 return true;163 }164
165 }