关闭

【java并发】Callable与Future的应用

标签: java并发线程CallableFuture
4186人阅读 评论(4) 收藏 举报
分类:

  Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。而Callable可以返回一个结果,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值,下面来看一个简单的例子:

public class CallableAndFuture {

    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();// 创建一个线程即可
        Future<String> future = threadPool.submit(
                new Callable<String>() {

                    @Override
                    public String call() throws Exception {
                        Thread.sleep(2000);
                        return "hello";
                    }
                }   
            );
        System.out.println("等待结果:");
        try {
            System.out.println("拿到结果:" + future.get());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
}

  使用并发库创建一个线程,前面博文已经提到过,如果调用execute方法,要传进去一个Runnable,现在我调用submit方法,就可以传进去一个Callable了,然后重写call方法,即可返回一个我们需要的数据,然后我们用Future来接收返回的数据,通过future.get()方法就可以取到。
  那么问题来了,这样做不是更加麻烦?我还不如直接去调用一个方法,然后返回一个值,我立马就拿到了啊,干嘛搞得这么麻烦!说的是有道理的,但是Callable和Future这个组合的用处不在于此。假设有一个很耗时的返回值需要计算,并且这个返回值不是立刻需要的话,那么就可以使用这个组合,用另一个线程去计算返回值,而当前线程在使用这个返回值之前可以做其它的操作,等到需要这个返回值时,再通过Future得到,这样设计岂不是很好?
  官方对Future有如下介绍:

Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。

  查看JDK文档,有个cancel方法是用来取消任务的,也就是说我们可以人为取消,这就比较灵活了,就像上面所说的,计算量比较大的时候,如果在不同情况下,是否需要去计算是不确定的,如果xxx,就让它算出结果,如果xxx,就不用计算了,那我们可以很灵活的使用这个Future,另外,在取消前,也可以先判断是否已经执行完了。都有相关方法的。
  
  上面是单个线程执行的情况,现在如果有多个线程都在执行,且有多个返回值,该怎么做呢?这种情况下,我们就要使用CompletionService<T>接口了,看一下具体的代码:

public class CallableAndFuture {

    public static void main(String[] args) {

        ExecutorService threadPool = Executors.newCachedThreadPool();//定义一个缓存线程池
        CompletionService<Integer> completionService = 
                new ExecutorCompletionService<Integer>(threadPool); //将线程池扔进去
        for(int i = 1; i <= 5; i ++) {
            final int seq = i;
            completionService.submit( //用里面装的线程去执行这些任务,每个线程都会返回一个数据
                    new Callable<Integer> () {

                        @Override
                        public Integer call() throws Exception {
                            Thread.sleep(new Random().nextInt(5000));
                            return seq;
                        }

                    }
                );
        }
        for(int i = 0; i < 5; i ++) { //执行完了后,再取出来
            try {
                System.out.print(completionService.take().get() + " ");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
        }
    }   
}

  这种方式和上面的方式有个区别是,上面单个线程的时候,使用ExecutorService对象去执行submit,多个线程的时候就把线程池扔到CompletionService<T>中去,然后执行submit,最后我们在调用take()和get()方法取出结果即可。使用起来比较方便,下面来看一下JDK文档对其的介绍:

  将生产新的异步任务与使用已完成任务的结果分离开来的服务。生产者 submit 执行的任务。使用者 take 已完成的任务,并按照完成这些任务的顺序处理它们的结果。
  通常,CompletionService 依赖于一个单独的 Executor 来实际执行任务,在这种情况下,CompletionService 只管理一个内部完成队列。

  官方介绍跟上面写的程序是一致的,首先take获取已完成的任务,然后get将每个任务拿到。并且按照完成这些任务的顺序处理它们,也就是说,刚刚在执行的时候,哪个线程先执行的,就会先拿到该线程执行的结果。
  

  相关阅读:http://blog.csdn.net/column/details/bingfa.html


—–乐于分享,共同进步!
—–更多文章请看:http://blog.csdn.net/eson_15

5
0
查看评论

JAVA 并发编程-返回执行结果(Callable和Future)(九)

启动一个线程不论使用Thread或者Runnable的时候,都是没有返回结果的。也就是说Thread和Runnable的run()方法必须没有返回值。   public void run(){} 解决方案: Callable和Future,一个产生结果,一个拿...
  • hejingyuan6
  • hejingyuan6
  • 2015-07-30 10:12
  • 4096

高级并发编程学习-callable与Future的使用

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线...
  • leixingbang1989
  • leixingbang1989
  • 2016-01-11 19:05
  • 1659

Java线程(七):Callable和Future

接着上一篇继续并发包的学习,本篇说明的是Callable和Future,它俩很有意思的,一个产生结果,一个拿到结果。        Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结果,并且无法抛出返回结果的异常...
  • ghsau
  • ghsau
  • 2016-02-05 15:12
  • 220235

Java Callable接口应用举例

Runnable是执行工作的独立任务,但是它不返回任何值。在Java SE5中引入的Callable是一种具有类型参数的泛型,它的类型参数表的是从方法call()中返回的值,并且必须使用ExecutorServices.submit()方法调用它,下面是一个简单示例。 package com.tes...
  • xin_jmail
  • xin_jmail
  • 2014-03-26 14:42
  • 12506

Java并发编程:Callable、Future和FutureTask原理解析

返回结果的任务Callable与FutureExecutor框架使用Runnable作为其基本的任务表示形式。Runnable是一种有很大局限的抽象,它不能返回一个值或抛出一个受检查的异常。Runnable接口:public interface Runnable { public abstr...
  • codershamo
  • codershamo
  • 2016-07-13 20:00
  • 5435

Java并发编程:Callable和Future使用

在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口。然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果。我们一般只能采用共享变量或共享存储区以及线程通信的方式实现获得任务结果的目的。 不过,Java中,也提供了使用Callable和Future...
  • u013405574
  • u013405574
  • 2016-04-06 13:32
  • 2766

Java并发编程(Callable、Future和CompletionService)

上篇博客主要讲解了一下java并发编程中的线程池,这篇呢来谈一下,java并发编程中的任务管理。这篇博客主要涉及到的Future、CompletionService、callable、runnable接口。    runnable接口    可以看看这个接口...
  • ZHOUCHAOQIANG
  • ZHOUCHAOQIANG
  • 2015-09-04 18:11
  • 1456

Java并发编程-Executor框架之Callable和Future接口

在上一篇文章中我们已经了解了Executor框架进行线程管理,这篇文章将学习Executor框架的另一个特性,我们知道执行Runnable任务是没有返回值得,但Executor可以运行并发任务并获得返回值,Concurrent包提供下面两个接口实现这个功能: Callable接口:这个接口声明cal...
  • chenchaofuck1
  • chenchaofuck1
  • 2016-06-07 20:58
  • 3508

Java异步并发Callable与Runable

Future到底是什么东西?很多人都对这个东西感到特别奇怪(好吧,我承认,那个很多人就只是我自己而已),就我现在的理解,因为本人在并发这方面没有多少实践经验,所以只好就着一些资料和自己的理解给它下个定义,Future就是保存我们任务的完成信息,比如说,任务中会通过返回某些东西告诉别人它已经结束了,而...
  • u010061691
  • u010061691
  • 2016-01-26 14:40
  • 2341

理解高并发(15).Future、Callable实现原理及用法

概述 jdk1.5推出的,使用它能带来2个方便: 能够获得到线程执行后返回的结果 线程异常有效捕获 简单例子 输出结果:result=hello public class ThreadLocalTest { @SuppressWarnings("unchecked") ...
  • maozhr720
  • maozhr720
  • 2017-08-26 21:59
  • 143
    个人资料
    • 访问:1639537次
    • 积分:16151
    • 等级:
    • 排名:第780名
    • 原创:163篇
    • 转载:5篇
    • 译文:0篇
    • 评论:1687条
    友情链接
    博客专栏
    休闲时刻
      学累了吗?用鼠标逗逗它吧^_^