多线程环境中,比较掌握的事情之一就是如何返回线程的信息。因为run和start方法并不返回任何值。
假设现在有两个线程,主线程和一个子线程,子线程读文件,主线程需要对文件的结果进行操作,当然,最简单的方法就是读文件和处理读出的文件全部都在主线程中进
行。
线程如何返回信息? 首先,采用轮询的方法:
public static void main(String[] args) throws Exception {
File[] files = new File[5];
ReadFileThread rft = new ReadFileThread(new File("test4.txt"));
rft.start();
//rft.join();
/*需要一个好的方法,来保证 getContent在content准备好之前就调用*/
//System.out.println(rft.getContent());
/*采用轮询的方法*/
StringBuffer content = null;
while(true) {
content = rft.getContent();
if(content.length() > 0) {
System.out.println("文件内容为:" + content);
System.out.println("文件内容长度为:"+content.length());
break;
}
}
}
/*采用回调的方式,此方法为回调方法, 将会在子线程中调用*/
public static void receiveContent(StringBuffer content) {
System.out.println("文件内容为:" + content);
System.out.println("文件内容长度为:"+content.length());
}
}
class ReadFileThread extends Thread {
/*File对象引用*/
private File file;
/* content成员 */
private StringBuffer content;
/*获取文件内容方法*/
public StringBuffer getContent() {
return this.content;
}
/*构造函数初始化*/
public ReadFileThread(File file) {
this.file = file;
this.content = new StringBuffer();
}
/*线程run方法,读文件*/
public void run() {
try {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String temp = "";
while( (temp=br.readLine()) != null ) {
content.append(temp);
}
br.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
上面这种轮询的方法,只需要在主线程中不停的调用getContent方法,如果有数据则进行处理,这里的处理仅仅是将数据输出到控制台。这个方案能起到作用,但是在主线程中使
用一个循环来不断询问ReadFileThread类对象的getContent方法,浪费了很多CPU循环。轮询的方法实际上是主线程不断的询问子线程读取是否结束,其实可以反过来,如果子线程
读取数据结束,则通知主线程,这种方法可以称之为回调。修改后的代码:
这种回调的方案,实际上是在读取数据完成后调用了主线程类的一个静态方法,这个静态方法最终是在子线程中运行。也可以将主线程类对象传入到子线程中,调用非静态方法来
实现。
还有更复杂的情况 : 如果有多个对象关心线程的计算结果,那么线程可以保存一个回调对象列表。某个对象可以通过调用Thread或 Runnable类的一个方法,把自己添加到列表中
,表示自己对计算结果有兴趣。如果有多个类的实例对象关心读取结果,可以定义一个接口,所有类都要实现这个接口。此接口将会声明一个回调方法。这种方式其实就是在AWT中
处理事件的方式。 AWT在单独的线程中运行,其它组件通过回调在某个接口中声明的方法来通知事件的发生,比如按钮事件监听器ActionListener。
下面的代码模拟了这种方案:
public ListCallback(File file) {
this.file = file;
}
/* 加入到队列中 */
public synchronized void addProcessListener(ProcessListener pl) {
this.listListener.add(pl);
}
/* 从队列中删除 */
public synchronized void removeProcessListener(ProcessListener pl) {
this.listListener.remove(pl);
}
/* 遍历集合中的对象,这些对象 */
private synchronized void sendContent(StringBuffer content) {
ListIterator iterator = this.listListener.listIterator();
/* 循环遍历 */
while(iterator.hasNext()) {
ProcessListener pl = (ProcessListener)iterator.next();
/* 调用关注结果数据的对象的处理方法 */
pl.processResult(content);
}
}
/* 读取数据 */
public void run() {
try {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String temp = "";
StringBuffer content = new StringBuffer();
while( (temp=br.readLine()) != null ) {
content.append(temp);
}
/*读取成功后,传入sendContent方法中*/
this.sendContent(content);
br.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*调用此方法创建ListCallback对象,并将当前对象添加到队列中,启动线程*/
public void cal() {
ListCallback lc = new ListCallback(file);
lc.addProcessListener(this);
Thread t = new Thread(lc);
t.start();
}
/*处理结果*/
public void processResult(StringBuffer content) {
this.content = content;
System.out.println(content);
}
public static void main(String[] args) {
/* 在工程目录下定义了四个文件 ,test1.txt, test2.txt, test3.txt, test4.txt*/
for (int i = 1; i <= 4; i++) {
File file = new File("test"+i+".txt");
UserProcess uprocess = new UserProcess(file);
uprocess.cal();
}
}
}