最近研究了一下异步调用,接下来几篇博客是跟异步调用相关的,首先使用@FunctionalInterface接口实现一个简单的步调用,也就是本篇博客主要内容。
然后再加上ZMQ,实现一个带网络通信的异步调用。再下一步就是复杂一点的RPC调用,最终目的是实现一个使用ZMQ的分布式调用系统。
Flag已经立,目标也定好了,先从简单的说起。
情景假设:假设一个程序需求是用户Person查看用户密码,这个需要访问数据库,可能是耗时操作,把这个做成异步调用。
1 @FunctionalInterface介绍:
FunctionalInterface的接口被称为函数式接口,该接口只能有一个自定义方法,但是可以包括从object类继承而来的方法。如果一个接口只有一个方 法,则编译器会认为这就是一个函数式接口
定义一个@FunctionalInterface接口:
- package com.zjq.java8.methodInterface;
- @FunctionalInterface
- public interface GofFunction<T1,T2> {
- public void execute(T1 t1,T2 t2);
- }
- package com.zjq.java8.methodInterface;
- import java.util.HashMap;
- import java.util.Map;
- public class ParamContext {
- private Map<String,Object> datas=new HashMap<String,Object>();
- public ParamContext(Object...params){
- if(params==null||params.length==0){
- return;
- }
- for(int i=0;i<params.length;){
- datas.put((String) params[i], params[i+1]);
- i+=2;
- }
- }
- @SuppressWarnings("unchecked")
- public <R> R get(String key){
- return (R)datas.get(key);
- }
- }
- package com.zjq.java8.methodInterface;
- import java.util.UUID;
- import java.util.concurrent.ConcurrentHashMap;
- public class ListenCall {
- ConcurrentHashMap<String,GofFunction<ParamContext, ParamContext>> methodMap=new ConcurrentHashMap<String,GofFunction<ParamContext, ParamContext>>();
- ConcurrentHashMap<String,ParamContext> paramMap=new ConcurrentHashMap<String,ParamContext>();
- /**
- * 获取请求编号
- * @return
- */
- public String getCallId(){
- UUID uuid = UUID.randomUUID();
- return uuid.toString();
- }
- /**
- * 监听返回值
- * @param method
- * @param callId
- * @param context
- */
- public void listenResult(GofFunction<ParamContext, ParamContext> method,String callId,ParamContext context) {
- methodMap.put(callId, method);
- paramMap.put(callId, context);
- }
- /**
- * 等待处理结果
- * @param result
- * @param callId
- */
- public void waitForResult(ParamContext result,String callId){
- GofFunction<ParamContext, ParamContext> funtion=methodMap.get(callId);
- if(funtion!=null){
- ParamContext context=paramMap.get(callId);
- if(context==null){
- context=new ParamContext();
- }
- funtion.execute(result,context);
- }
- }
- }
- package com.zjq.java8.methodInterface;
- public class PersonService {
- private ListenCall listenCall=new ListenCall();
- /**
- * 这里模拟根据用户名从数据库查询密码
- * @param name 用户名
- * @param callId 请求调用的id
- */
- public void getPwdFromDb(String name,String callId){
- new Thread(new Runnable() {
- @Override
- public void run() {
- String sql="select from person where name="+"'"+name+"'";
- String pwd="1111";
- try {
- //这里等待4秒,模拟毒区数据库的书剑,时间有点夸张
- Thread.sleep(4000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- waitForResult(new ParamContext("pwd",pwd),callId);
- }
- }).start();
- }
- public String getCallId(){
- return listenCall.getCallId();
- }
- public void waitForResult(ParamContext p,String callId){
- listenCall.waitForResult(p, callId);
- }
- public void listenResult(GofFunction<ParamContext, ParamContext> method,String callId,ParamContext context){
- listenCall.listenResult(method, callId, context);
- }
- }
- package com.zjq.java8.methodInterface;
- public class PersonManager {
- PersonService personService=new PersonService();
- public static void main(String[] args) {
- PersonManager callTest=new PersonManager();
- callTest.seePwd();
- }
- /**
- * 假设用户想查看一下密码
- */
- private void seePwd(){
- String name="1111";
- String time=String.valueOf(System.currentTimeMillis());
- String callId=personService.getCallId();
- personService.getPwdFromDb(name,callId);
- personService.listenResult(this::getPwd,callId,new ParamContext("time",time));
- System.out.println("数据库读取数据,可能有点耗时,这里做成异步操作,我先做其他事情。。。。。。。。。");
- }
- /**
- * 获取到了密码
- * @param result
- * @param context
- */
- private void getPwd(ParamContext result,ParamContext context){
- String pwd=result.get("pwd");
- long sed=(System.currentTimeMillis()-Long.valueOf(context.get("time")))/1000;
- System.out.println("经过"+sed+"秒"+"查询用户密码的调用终于返回了");
- System.out.println("得到密码:"+pwd);
- }
- }
- 数据库读取数据,可能有点耗时,这里做成异步操作,我先做其他事情。。。。。。。。。
- 经过4秒查询用户密码的调用终于返回了
- 得到密码:1111