Java并发编程学习-日记4、 Future异步回调

JION   

 join操作的原理是:阻塞当前的线程,直到准备合并的目标线程的执行。在Java中,线程(Thread)的合并流程是:假设线程A调用了线程B的B.join方法,合并B线程。那么,线程A进入阻塞状态,直到B线程执行完成

(1)join是实例方法,不是静态方法,需要使用线程对象去调用,如thread.join()。

(2)join调用时,不是线程所指向的目标线程阻塞,而是当前线程阻塞。

(3)只有等到当前线程所指向的线程执行完成,或者超时,当前线程才能重新恢复执行。

(4)join有一个问题:被合并的线程没有返回。

Java Future

      Runnable的run方法是没有返回值的,正因为如此,Runnable不能用于需要有返回值的应用场景。此时可以使用Callable接口。但Callable接口的实例不能作为Thread线程实例的target来使用;而Runnable接口实例可以作为Thread线程实例的target构造参数,开启一个Thread线程。Java提供了在Callable实例和Thread的target成员之间一个搭桥的类——FutureTask类。

FutureTask类代表一个未来执行的任务,表示新线程所执行的操作。FutureTask类的构造函数的参数为Callable类型,实际上是对Callable类型的二次封装,可以执行Callable的call方法。FutureTask类间接地继承了Runnable接口,从而可以作为Thread实例的target执行目标。FutureTask类的get方法,获取异步结果时,主线程也会被阻塞的。这一点,FutureTask和join也是一样的,它们俩都是异步阻塞模式。如果需要用到获取异步的结果,则需要引入一些额外的框架,如谷歌的Guava。

Guava Future

Guava的异步任务接口ListenableFuture,扩展了Java的Future接口,实现了非阻塞获取异步结果的功能。Guava对Java的异步回调机制,做了以下的增强:

(1)引入了一个新的接口ListenableFuture,继承了Java的Future接口,使得Java的Future异步任务,在Guava中能被监控和获得非阻塞异步执行的结果。

(2)引入了一个新的接口FutureCallback,这是一个独立的新接口。该接口的目的,是在异步任务执行完成后,根据异步结果,完成不同的回调处理,并且可以处理异步结果。

Guava线程池,是对Java线程池的一种装饰。首先创建Java线程池,然后以它作为Guava线程池的参数,再构造一个Guava线程池。

Guava异步回调的流程如下:

第1步:实现Java的Callable接口,创建异步执行逻辑。还有一种情况,如果不需要返回值,异步执行逻辑也可以实现Java的Runnable接口。

第2步:创建Guava线程池。

第3步:将第1步创建的Callable/Runnable异步执行逻辑的实例,通过submit提交到Guava线程池,从而获取ListenableFuture异步任务实例。

第4步:创建FutureCallback回调实例,通过Futures.addCallback将回调实例绑定到ListenableFuture异步任务上。

Java Join、Java Future、Guava Future实践

Java Join

Java Future

Guava Future

/*主线程合并烧水和清洗线程后,主线程堵塞,

等待完成后再执行;join有三个重载方法,可以设置等待时间*/

/*

实现Callable的call()方法,可以获取到线程的直接结果。

这里简单的返回了Boolean类型。

根据返回的结果主线程决定下一步的业务处理逻辑。

但是要注意的是,线程的创建需要借助FutureTask

*/

/*

Guava通过Futures的addCallback,对绑定的结果进行一步处理。处理回调逻辑绑定在FutureCallback中。

*/

public class JoinDemo {

    public static final int SLEEP_GAP = 5000;

    public static String getCurThreadName() {

        return Thread.currentThread().getName();

    }

    static class HotWaterThread extends Thread {

        public HotWaterThread() {

            super("** 烧水-Thread");

        }

        public void run() {

            try {

                Logger.info("洗好水壶");

                Logger.info("灌上凉水");

                Logger.info("放在火上");

                //线程睡眠一段时间,代表烧水中

                Thread.sleep(SLEEP_GAP);

                Logger.info("水开了");

            } catch (InterruptedException e) {

                Logger.info(" 发生异常被中断.");

            }

            Logger.info(" 运行结束.");

        }

    }

    static class WashThread extends Thread {

        public WashThread() {

            super("$$ 清洗-Thread");

        }

        public void run() {

            try {

                Logger.info("洗茶壶");

                Logger.info("洗茶杯");

                Logger.info("拿茶叶");

                //线程睡眠一段时间,代表清洗中

                Thread.sleep(SLEEP_GAP);

                Logger.info("洗完了");

            } catch (InterruptedException e) {

                Logger.info(" 发生异常被中断.");

            }

            Logger.info(" 运行结束.");

        }

    }

    public static void main(String args[]) {

        Thread hThread = new HotWaterThread();

        Thread wThread = new WashThread();

        hThread.start();

        wThread.start();

        try {

            // 合并烧水-线程

            hThread.join();

            // 合并清洗-线程

            wThread.join();

            Thread.currentThread().setName("主线程");

            Logger.info("泡茶喝");

        } catch (InterruptedException e) {

            Logger.info(getCurThreadName() + "发生异常被中断.");

        }

        Logger.info(getCurThreadName() + " 运行结束.");

    }

}

public class JavaFutureDemo {

    public static final int SLEEP_GAP = 5000;

    public static String getCurThreadName() {

        return Thread.currentThread().getName();

    }

    static class HotWaterJob implements Callable<Boolean> 

    {

        @Override

        public Boolean call() throws Exception 

        {

            try {

                Logger.info("洗好水壶");

                Logger.info("灌上凉水");

                Logger.info("放在火上");

                //线程睡眠一段时间,代表烧水中

                Thread.sleep(SLEEP_GAP);

                Logger.info("水开了");

            } catch (InterruptedException e) {

                Logger.info(" 发生异常被中断.");

                return false;

            }

            Logger.info(" 运行结束.");

            return true;

        }

    }

    static class WashJob implements Callable<Boolean> {

        @Override

        public Boolean call() throws Exception {

            try {

                Logger.info("洗茶壶");

                Logger.info("洗茶杯");

                Logger.info("拿茶叶");

                //线程睡眠一段时间,代表清洗中

                Thread.sleep(SLEEP_GAP);

                Logger.info("洗完了");

            } catch (InterruptedException e) {

                Logger.info(" 清洗工作 发生异常被中断.");

                return false;

            }

            Logger.info(" 清洗工作  运行结束.");

            return true;

        }

    }

    public static void drinkTea(boolean waterOk, boolean cupOk) {

        if (waterOk && cupOk) {

            Logger.info("泡茶喝");

        } else if (!waterOk) {

            Logger.info("烧水失败,没有茶喝了");

        } else if (!cupOk) {

            Logger.info("杯子洗不了,没有茶喝了");

        }

    }

    public static void main(String args[]) {

Callable<Boolean> hJob = new HotWaterJob();

        FutureTask<Boolean> hTask = new FutureTask<>(hJob);

        Thread hThread = new Thread(hTask, "** 烧水-Thread");

        Callable<Boolean> wJob = new WashJob();

        FutureTask<Boolean> wTask = new FutureTask<>(wJob);

        Thread wThread = new Thread(wTask, "$$ 清洗-Thread");

        hThread.start();

        wThread.start();

        Thread.currentThread().setName("主线程");

        try {

            boolean  waterOk = hTask.get();

            boolean  cupOk = wTask.get();

            drinkTea(waterOk, cupOk);

        } catch (InterruptedException e) {

            Logger.info(getCurThreadName() + "发生异常被中断.");

        } catch (ExecutionException e) {

            e.printStackTrace();

        }

        Logger.info(getCurThreadName() + " 运行结束.");

    }

}

public class GuavaFutureDemo {

    public static final int SLEEP_GAP = 5000;

    public static String getCurThreadName() {

        return Thread.currentThread().getName();

    }

    static class HotWaterJob implements Callable<Boolean> 

    {

        @Override

        public Boolean call() throws Exception 

        {

            try {

                Logger.info("洗好水壶");

                Logger.info("灌上凉水");

                Logger.info("放在火上");

                //线程睡眠一段时间,代表烧水中

                Thread.sleep(SLEEP_GAP);

                Logger.info("水开了");

            } catch (InterruptedException e) {

                Logger.info(" 发生异常被中断.");

                return false;

            }

            Logger.info(" 烧水工作,运行结束.");

            return true;

        }

    }

    static class WashJob implements Callable<Boolean> {

        @Override

        public Boolean call() throws Exception {

            try {

                Logger.info("洗茶壶");

                Logger.info("洗茶杯");

                Logger.info("拿茶叶");

                //线程睡眠一段时间,代表清洗中

                Thread.sleep(SLEEP_GAP);

                Logger.info("洗完了");

            } catch (InterruptedException e) {

                Logger.info(" 清洗工作 发生异常被中断.");

                return false;

            }

            Logger.info(" 清洗工作  运行结束.");

            return true;

        }

    }

    //泡茶线程

    static class MainJob implements Runnable {

        boolean waterOk = false;

        boolean cupOk = false;

        int gap = SLEEP_GAP / 10;

        @Override

        public void run() {

            while (true) {

                try {

                    Thread.sleep(gap);

                    Logger.info("读书中......");

                } catch (InterruptedException e) {

                    Logger.info(getCurThreadName() + "发生异常被中断.");

                }

                if (waterOk && cupOk) {

                    drinkTea(waterOk, cupOk);

                }

            }

        }

        public void drinkTea(Boolean wOk, Boolean cOK) {

            if (wOk && cOK) {

                Logger.info("泡茶喝,茶喝完");

                this.waterOk = false;

                this.gap = SLEEP_GAP * 100;

            } else if (!wOk) {

                Logger.info("烧水失败,没有茶喝了");

            } else if (!cOK) {

                Logger.info("杯子洗不了,没有茶喝了");

            }

        }

    }

    public static void main(String args[]) {

        //新起一个线程,作为泡茶主线程

        MainJob mainJob = new MainJob();

        Thread mainThread = new Thread(mainJob);

        mainThread.setName("主线程");

        mainThread.start();

        //烧水的业务逻辑

        Callable<Boolean> hotJob = new HotWaterJob();

        //清洗的业务逻辑

        Callable<Boolean> washJob = new WashJob();

        //创建java 线程池

        ExecutorService jPool = Executors.newFixedThreadPool(10);

        //包装java线程池,构造guava 线程池

        ListeningExecutorService gPool = MoreExecutors.listeningDecorator(jPool);

        //提交烧水的业务逻辑,取到异步任务

        ListenableFuture<Boolean> hotFuture = gPool.submit(hotJob);

        //绑定任务执行完成后的回调,到异步任务

        Futures.addCallback(hotFuture, new FutureCallback<Boolean>() {

            public void onSuccess(Boolean r) {

                if (r) {

                    mainJob.waterOk = true;

                }

            }

            public void onFailure(Throwable t) {

                Logger.info("烧水失败,没有茶喝了");

            }

        });

        //提交清洗的业务逻辑,取到异步任务

        ListenableFuture<Boolean> washFuture = gPool.submit(washJob);

        //绑定任务执行完成后的回调,到异步任务

        Futures.addCallback(washFuture, new FutureCallback<Boolean>() {

            public void onSuccess(Boolean r) {

                if (r) {

                    mainJob.cupOk = true;

                }

            }

            public void onFailure(Throwable t) {

                Logger.info("杯子洗不了,没有茶喝了");

            }

        });

    }

}

Guava异步回调和Java FutureTask异步回调的本质不同

  • Guava是非阻塞的异步回调,调用线程是不阻塞的,可以继续执行自己的业务逻辑。
  • FutureTask是阻塞的异步回调,调用线程是阻塞的,在获取异步结果的过程中,一直阻塞,等待异步线程返回结果。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值