1. 低调自然的回调理念
多线程嘛,就是老板同时安排多个人去完成工作,老板当然希望能知道每个工作的完成情况。
最简单的想法,可以轮询,就是老板每隔一段时间,就去问下每个人工作完成了没。这个方法可行吗,当然可行,但是非常浪费老板的时间啊,老板铁定不开心。
那么怎么做比较好呢,当然是每个人完成了自己的工作后进行汇报,将工作结果汇报给老板。
这种线程执行完成后主动告知主程序结果的方式,被称之为回调(Callback)。
不要被Callback这种看似高端大气的名词唬住,其实回调是非常低调、自然、常见的思维理念。
2. 回调静态方法
由于静态方法是全局通用的,所以我们可以非常容易的在线程中回调主程序中的静态方法。
先看线程,执行结束后回调主程序的静态方法来告诉主程序执行结果。
/**
* 员工:负责读取文件大小
*/
public class ReadFileMan implements Runnable {
/**
* 文件名
*/
private String fileName;
public ReadFileMan(String fileName) {
this.fileName = fileName;
}
@Override
public void run() {
File f = new File(fileName);
if (f.exists() && f.isFile()) {
// 回调主程序的静态方法
ReadFileBoss.knowFileLength(fileName, f.length());
} else {
// 回调主程序的静态方法
ReadFileBoss.knowFileLength(fileName, f.length());
}
}
}
主程序比较简单,启动线程,然后等待回调即可:
/**
* 主程序
*/
public class ReadFileBoss {
public static void knowFileLength(String fileName, long length) {
System.out.println("老板知道了文件[" + fileName + "]大小:" + length);
}
public static void main(String[] args) {
// 启动线程
ReadFileMan readFileMan = new ReadFileMan("D:\\temp\\1.txt");
Thread thread = new Thread(readFileMan);
thread.start();
// 输出:老板知道了文件[D:\temp\1.txt]大小:6
}
}
在上面的程序中,老板ReadFileBoss告诉员工readFileMan去读取文件大小后,只需要等待员工上报结果即可。
对员工来说,执行完毕后直接回调老板的静态方法,很容易。
3. 回调实例方法
还有一种方法是回调实例方法,这种模式相当于每个员工有一个经理,负责管理员工的日常行为并监督执行结果,老板只要管理经理即可,员工只需要向经理汇报。
OK,员工线程需要知道自己的经理是谁,所以修改如下:
/**
* 员工:负责读取文件大小
*/
public class ReadFileMan implements Runnable {
/**
* 文件名
*/
private String fileName;
/**
* 员工需要知道自己的经理是谁
*/
private ReadFileManager readFileManager;
public ReadFileMan(String fileName, ReadFileManager readFileManager) {
this.fileName = fileName;
this.readFileManager = readFileManager;
}
@Override
public void run() {
File f = new File(fileName);
if (f.exists() && f.isFile()) {
// 回调经理的实例方法
readFileManager.knowFileLength(fileName, f.length());
} else {
// 回调经理的静态方法
readFileManager.knowFileLength(fileName, f.length());
}
}
}
经理需要安排员工去工作,然后经理还需要管理工作结果。
/**
* 经理
*/
public class ReadFileManager {
/**
* 执行结果
*/
public void knowFileLength(String fileName, long length) {
System.out.println("经理知道了文件[" + fileName + "]大小:" + length);
System.out.println("经理根据工作情况进行进一步处理");
}
/**
* 安排工作
*/
public void plan() {
// 启动线程
ReadFileMan readFileMan = new ReadFileMan("D:\\temp\\1.txt", this);
Thread thread = new Thread(readFileMan);
thread.start();
}
}
老板就轻松了,直接让经理去负责:
/**
* 主程序
*/
public class ReadFileBoss {
public static void main(String[] args) {
// 把事情交给经理就行了
ReadFileManager manager=new ReadFileManager();
manager.plan();
// 执行结果:经理知道了文件[D:\temp\1.txt]大小:6
}
}
4. 小结
从上面的实例中能发现,让经理去管理时更好的,因为每个经理可以管理多个员工(多个员工线程回调一个经理实例即可);每个员工也可以汇报给多个经理(员工保存回调经理的列表);这样非常灵活。
让一个实例去管理线程,可以实现各种管理逻辑,便于拓展,也更加符合面向对象编程的思想。
所以建议采用通过实例方法回调获取线程数据。