多线程间通信---监视线程:
一、多线程间通信---监视线程:
用自己的话来说,就是线程间的通信,一个线程执行,同时用另一个线程来监视目标线程的运行状态.
二、以统计文件为例:
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方法.
通过看API发现:
1.文件夹也是有长度的
2.当文件是文件夹时,返回值是随机的,这个也就是可以解释为什么是负值的,和长度大小不一样的
七、补充:
在移除已经运行完毕的线程时,使用List.remove(i)的方法会出现:ConcurrentModificationException异常
ConcurrentModificationException异常:
原因是List里面的线程也在修改Collection.具体参见:
http://www.2cto.com/kf/201403/286536.html
八、总结:
经过这个,了解到了线程通信之监视线程,又给自己补课了