多线程间通信---监视线程:
?一、多线程间通信---监视线程:
?用自己的话来说,就是线程间的通信,一个线程执行,同时用另一个线程来监视目标线程的运行状态.
?
?二、以统计文件为例:
? 1.统计文件的线程类:
package 监控线程; import java.io.File; /** * 统计某一个磁盘的相关文件数据 * @author Administrator * */ public class CountFile extends Thread { private String rootDirName;//操作的根目录的名称 private int dirCount=0;//目录数量 private int realFileCount=0;//文件数量 private int lengthCount=0;//文件长度 private boolean finished =false;//是否运行结束 //传入根目录 public CountFile(String root){ this.rootDirName = root; } //线程进行计算: @Override public void run() { // TODO Auto-generated method stub //super.run(); long start=System.currentTimeMillis(); //System.out.println(start); lengthCount=countProcess(this.rootDirName); long timeCost=System.currentTimeMillis()-start; //System.out.println(timeCost); finished =true; } //统计文件长度,数量,文件夹个数 private int countProcess(String dir){ int count=0; File dirFile = new File(dir); if(!dirFile.exists()){//如果用户输入的目录不存在 return count; } File[] subFile=dirFile.listFiles(); if(subFile==null){ return count; } for(int i=0;i<subFile.length;i++){ if(subFile[i].isDirectory()){ dirCount++; count+=countProcess(subFile[i].getAbsolutePath()); } if(subFile[i].isFile()){ realFileCount++; count+=subFile[i].length(); } } //System.out.println("count数量:"+count); return count; } //线程是否结束 public boolean isFinished(){ return finished; } //打印结果 public String getResult(){ StringBuffer stb = new StringBuffer(); stb.append(rootDirName+"盘统计结果如下:\r\n"); stb.append("文件数量:"+realFileCount); stb.append("目录数量:"+dirCount); stb.append("文件总长度(单位:字节):"+lengthCount); return stb.toString(); } }
?
?2.监视线程类:
package 监控线程; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * 监控线程通讯模型: * 1.启动任务线程 * 2.对任务线程进行监视 * @author Administrator * */ public class MainCount implements Runnable { //保存统计线程对象的队列 private static List<CountFile> countList = new ArrayList(); public static void main(String[] args) { File[] rootFiles=File.listRoots(); for (int i = 0; i < rootFiles.length; i++) { CountFile cb = new CountFile(rootFiles[i].getAbsolutePath()); cb.start(); countList.add(cb);//将每个统计线程对象放入要监控的集合中 } System.out.println(rootFiles.length+"个统计线程已经启动"); //启动监视线程 new Thread(new MainCount()).start(); System.out.println("监视线程已经启动"); } //监控线程每隔3秒钟检测统计线程集合,看是否有 //完成统计的,如有完成,将其从集合中移除 @Override public void run() { // TODO Auto-generated method stub boolean flag =true; String result=""; while(flag){ //每隔一秒钟,检查一下队列中的线程对象的状态 Iterator<CountFile> it=countList.iterator(); while(it.hasNext()){ CountFile cf=it.next(); if (cf.isFinished()) {//如果这个线程已经统计完成 result+=cf.getResult()+"\r\n";//取得统计结果; //countList.remove(cf);//移除已经运行完毕的线程 it.remove(); } } //当统计线程队列为空时,说明所有的任务已执行完毕,本监视线程也要退出 if(countList.isEmpty()){ flag=false;//让统计线程结束 } try{ Thread.sleep(1000); }catch(Exception e){ } } System.out.println("并行统计结果如下:"); System.out.println(result); } }
?
?三、运行结果:
?
1.第1次运行结果:
?
?
2.第2次运行结果:
?
?四、我的盘:
?
?五、运行结果分析:
?通过我的盘,和两次的运行结果综合对比,发现两次的运行结果不一样的
,而且还出现负值
?
?六、查看资料:
File类的length方法.
?
?
? ? 1.文件夹也是有长度的
? ? 2.当文件是文件夹时,返回值是随机的,这个也就是可以解释为什么是负值的,和长度大小不一样的
?
?
七、补充:
? ?在移除已经运行完毕的线程时,使用List.remove(i)的方法会出现:ConcurrentModificationException异常
ConcurrentModificationException异常:
?
?原因是List里面的线程也在修改Collection.具体参见:
? ?http://www.2cto.com/kf/201403/286536.html
?
八、总结:
?经过这个,了解到了线程通信之监视线程,又给自己补课了
?
原文:http://cb123456.iteye.com/blog/2215584