java回调原理,以及Callable和FutureTask通过回调机制创建可监控的线程

回调的概念会JS的人应该都能理解。

回调分异步回调,同步回调。但是同步回调其实没什么意义。都同步了,那么直接等那边执行完了,这边再执行就可以了,没必要通过回调。我们说的回调主要是讲异步回调。用于两个线程甚至两个系统之间交互调用。

例如我在A类的方法funa()中,要调用B类的方法funb(),如果B类的方法会执行很久,但是A类方法中又还有部分后续任务需要等B执行完后才执行,又不愿意傻等B类方法执行完,怎么办?

解决办法:

    1,把需要等待B类执行完才能执行的后续任务放到一个方法中,把方法封装到一个类里面(也可以就放在A类里面)。A类方法在调用B类方法的时候,直接把自己这个对象也传过去。

2,在B类方法中,新建一个线程,让这个方法慢慢执行,关键是执行完了之后。B类方法中调用一下A类的封装的这个后续方法。

这就是回调了,大致的概念如此,具体的实现还是有些区别,比如通常实际中,不是要BA的后续任务作了,B只需要调用回调方法通知A做完了。我们回调方法,做成一个接口。让B类的入参是这个接口类。让A类实现这个接口并重写回调方法。

JAVA方法回调是功能定义和功能实现分享的一种手段,是一种耦合设计思想。作为一种架构,必须有自己的运行环境,并且提供用户的实现接口。

因为方法的回调是通过接口来实现的所以要定义一个接口

CallableFutureTask创建线程的方式,其实也是一种回调实现的方式,体现在那里呢?我们接着看:

我们知道线程执行的时候,是执行Runnable实现类的重写的void run()方法。

new Thread(new Runnable(){public void run(){…}}).start();

这个方法是没有返回值的。所以在线程结束之后,无法获取执行结果。(虽然也可以通过共享变量,和线程通信等方式来获取,但是比较麻烦)

如果想要线程执行有返回值,并且可以在一定程度上跟踪操作线程,那怎么办呢?于是就有了Callable和FutureTask。

Future就是对于具体的Runnable或者Callable任务的执行结果进行取消boolean cancel(boolean mayInterruptIfRunning);、查询是否完成boolean isDone();、获取结果get()。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

FutureTask是一个RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口。所以可以作为一个回调接口类,也可以作为线程的执行任务类。为了能够获取线程状态,那么执行方法肯定有一些相应的改动。在FutureTask的run方法中,我们不再是执行的具体任务,而是调用回调接口的实现方法,call(),并且监控call的执行情况,设置各种状态参数。其局部代码如下图所示:

这里只是局部的一些控制,还有一些状态参数,我也看得不是太懂- -!总之正如上文所说,线程真正要实现的任务放在了回调函数call()中并且可以设置返回值,Future中的run主要是对回调函数的调用,以及对回调函数执行状态的监视,以便在其他方法中(isDone,cancel)判断线程执行状态或者暂停线程时用到。

知道了,这些,我们要设计一个demo就ihen简单了,代码如下:

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * Created by tanjun on 2018/11/30.
 */
public class CallBakTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("通过callable和future方式启动线程。");
        Callable callf= new Callable<Map>(){  //使用map作为返回值,包含状态码
            @Override
            public Map call() throws Exception {
                Map m=new HashMap();
                try {
                    Thread.sleep(1000);//线程要执行的任务
                    m.put("code","1");//返回的执行状态-成功
                    m.put("msg",Thread.currentThread().getName()+"执行成功!");//返回的附带消息
                }catch(Exception e){
                    m.put("code","0");//返回的执行状态-成功
                    m.put("msg",Thread.currentThread().getName()+"执行失败!");//返回的附带消息
                }
                return m;
            }
        };
        FutureTask<Map> future=new FutureTask<>(callf);
        new Thread(future).start();
        System.out.println("主线程可以做其他事情...此时主线程事不需要阻塞的。");
        //接下来主线程要做根据子线程结果做相关的事情,这个时候,就可以阻塞等子线程执行完了。
        Map result= future.get();
        if("1".equals(result.get("code").toString())){
            System.out.println(result.get("msg"));
        }else{
            System.out.println(result.get("msg"));
        }

    }
}

猜你喜欢

转载自blog.csdn.net/tanjun592/article/details/84646028