Java 回调机制
接口回调是一种常见的设计模型,通常模块之间都有一定的调用关系,例如模块A 需要模块B 提供的某个服务,服务完成后将结果告诉模块A, 这时候模块 A 就需要告诉模块 B 一个联系方式,使 B 完成时来通知自己,这个场景就可以使用回调, 而这个联系方式就是回调接口Callback 。
同步式
假定有这样一个场景:有两个模块分别为主模块和Mysql 模块,主模块中间一个环节需要根据area 查询所有person, Mysql 模块提供这样的服务,于是主模块就需要调用Mysql 模块的服务,服务完成后将结果告诉主模块:
定义回调接口 CallBack
public interface CallBack
{
void success(List<String> persons);
}
主模块代码:
public class Main
{
public static void main(String[] args)
{
MysqlService.selectPersonsByArea("beijing" , new CallBack()
{
@Override
public void success(List<String> persons)
{
System.out.println("收到回调结果:"+String.join(",", persons));
}
});
System.out.println("主模块运行完成!!!");
}
}
Mysql 模块代码:
public class MysqlService
{
public static void selectPersonsByArea(String area, CallBack callBack)
{
// 模拟查询操作1s 阻塞
Thread.sleep(1000);
// 查询出属于本area 的persons
List<String> persons= Arrays.asList("lilei", "wangmiao", "heyue");
callBack.success(persons);
}
}
运行结果:
阻塞大概1s 后输出结果如下:
收到回调结果:lilei,wangmiao,heyue
主模块运行完成!!!
异步式
从上面的运行结果,我们可以知道,主模块会先运行完Mysql 模块的查询,才能执行下面的代码逻辑,即主模块阻塞在了Mysql 模块的查询,要是因为网络、Mysql 模块性能等问题,主模块的麻烦就大了…
所以我们需要将这块变为异步回调,Mysql 查询服务并不阻塞主模块,更改后如下:
public class MysqlService
{
private static final ThreadPoolExecutor pools = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(5));
public static void selectPersonsByArea(String area, CallBack callBack)
{
pools.execute(() ->
{
// 查询出属于本area 的persons
try
{
// 模拟查询阻塞1s
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
List<String> persons= Arrays.asList("lilei", "wangmiao", "heyue");
callBack.success(persons);
});
}
}
运行结果如下:
主模块首先输出:主模块运行完成!!!
然后阻塞1s 后输出: 收到回调结果:lilei,wangmiao,heyue
主模块运行完成!!!
收到回调结果:lilei,wangmiao,heyue