使用Java8的函数式接口@FunctionalInterface实现简单异步调用

  最近研究了一下异步调用,接下来几篇博客是跟异步调用相关的,首先使用@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);
}
2 定义一个参数包装类,可以包装任何参数:

 

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);
	}
}
3 定义一个监听类,里面有两个map,一个是所调用方法的map,一个是对应参数的map,map的key值是生成的uuid

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);
		}
		
	}

}
4 定义person的service类,里面有一些逻辑方法,有一个模拟读取数据库的方法,此方法是多线程的,模拟读取数据库,线程休眠4秒。

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);
	}
}
5 用户的管理类。

 

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);	
	}
}
6 程序执行结果:

数据库读取数据,可能有点耗时,这里做成异步操作,我先做其他事情。。。。。。。。。
经过4秒查询用户密码的调用终于返回了
得到密码:1111
分析,程序先打印的第一句,等4秒后才打印后面的,说明异步调用成功。



  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值