Hereby I am starting a series of articles about future concept in programming languages (also known as promises or delays) with a working title: Back to the Future. Futures are very important abstraction, even more these day than ever due to growing demand for asynchronous, event-driven, parallel and scalable systems. In the first article we'll discover most basic java.util.concurrent.Future<T> interface. Later on we will jump into other frameworks, libraries or even languages. Future<T> is pretty limited, but essential to understand, ekhm, future parts.

In a single-threaded application when you call a method it returns only when the computations are done (IOUtils.toString() comes from Apache Commons IO):

 
public String downloadContents(URL url) throws IOException {
 
    try(InputStream input = url.openStream()) {
 
        return IOUtils.toString(input, StandardCharsets.UTF_8);
 
    }
 
}
 
 
 
//...
 
 
 
final String contents = downloadContents(new URL("http://www.example.com"));
 

downloadContents() looks harmless1, but it can take even arbitrary long time to complete. Moreover in order to reduce latency you might want to do other, independent processing in the meantime, while waiting for results. In the old days you would start a new Thread and somehow wait for results (shared memory, locks, dreadful wait()/notify() pair, etc.) With Future<T> it's much more pleasant:

 
public static Future<String> startDownloading(URL url) {
 
    //...
 
}
 
 
 
final Future<String> contentsFuture = startDownloading(new URL("http://www.example.com"));
 
//other computation
 
final String contents = contentsFuture.get();
 

We will implement startDownloading() soon. For now it's important that you understand the principles. startDownloading() does not block, waiting for external website. Instead it returns immediately, returning a lightweight Future<String> object. This object is a promise that String will be available in the future. Don't know when, but keep this reference and once it's there, you'll be able to retrieve it using Future.get(). In other words Future is a proxy or a wrapper around an object that is not yet there. Once the asynchronous computation is done, you can extract it. So what API does Future provide?

Future.get() is the most important method. It blocks and waits until promised result is available (resolved). So if we really need that String, just call get() and wait. There is an overloaded version that accepts timeout so you won't wait forever if something goes wild. TimeoutException is thrown if waiting for too long.

In some use cases you might want to peek on the Future and continue if result is not yet available. This is possible with isDone().
Imagine a situation where your user waits for some asynchronous
computation and you'd like to let him know that we are still waiting and
do some computation in the meantime:

 
final Future<String> contentsFuture = startDownloading(new URL("http://www.example.com"));
 
while (!contentsFuture.isDone()) {
 
    askUserToWait();
 
    doSomeComputationInTheMeantime();
 
}
 
contentsFuture.get();
 

The last call to contentsFuture.get() is guaranteed to return immediately and not block because Future.isDone() returned true. If you follow the pattern above make sure you are not busy waiting, calling isDone() millions of time per second.

Cancelling futures is the last aspect we have not covered yet. Imagine
you started some asynchronous job and you can only wait for it given
amount of time. If it's not there after, say, 2 seconds, we give up and
either propagate error or work around it. However if you are a good
citizen, you should somehow tell this future object: I no longer need
you, forget about it. You save processing resources by not running
obsolete tasks. The syntax is simple:

 
contentsFuture.cancel(true);    //meh...
 

We all love cryptic, boolean parameters, aren't we? Cancelling comes in two flavours. By passing false to mayInterruptIfRunning parameter we only cancel tasks that didn't yet started, when the Future represents results of computation that did not even began. But if our Callable.call() is already in the middle, we let it finish. However if we pass true, Future.cancel() will be more aggressive, trying to interrupt already running jobs as well. How? Think about all these methods that throw infamous InterruptedException, namely Thread.sleep(), Object.wait(), Condition.await(), and many others (including Future.get()). If you are blocking on any of such methods and someone decided to cancel your Callable, they will actually throw InterruptedException, signalling that someone is trying to interrupt currently running task.


So we now understand what

Future<T>

is - a place-holder for something, that you will get in the
future. It's like keys to a car that was not yet manufactured. But how
do you actually obtain an instance of

Future<T>

in your application? Two most common sources are thread
pools and asynchronous methods (backed by thread pools for you). Thus
our

startDownloading()

method can be rewritten to:

 
private final ExecutorService pool = Executors.newFixedThreadPool(10);
 
 
 
public Future<String> startDownloading(final URL url) throws IOException {
 
    return pool.submit(new Callable<String>() {
 
        @Override
 
        public String call() throws Exception {
 
            try (InputStream input = url.openStream()) {
 
                return IOUtils.toString(input, StandardCharsets.UTF_8);
 
            }
 
        }
 
    });
 
}
 

A lot of syntax boilerplate, but the basic idea is simple: wrap long-running computations in

Callable<String>

and

submit()

them to a thread pool of 10 threads. Submitting returns some implementation of

Future<String>

, most likely somehow linked to your task and thread pool. Obviously your task is not executed immediately. Instead it is placed in a queue which is later (maybe even much later) polled by thread from a pool. Now it should be clear what these two flavours of

cancel()

mean - you can always cancel task that still resides in that queue. But cancelling already running task is a bit more complex.

Another place where you can meet

Future

is Spring and EJB. For example in Spring framework you can simply annotate your method with @Async:

 
@Async
 
public Future<String> startDownloading(final URL url) throws IOException {
 
    try (InputStream input = url.openStream()) {
 
        return new AsyncResult<>(
 
                IOUtils.toString(input, StandardCharsets.UTF_8)
 
        );
 
    }
 
}
 

Notice that we simply wrap our result in AsyncResult implementing

Future

. But the method itself does not deal with thread pool or asynchronous processing. Later on Spring will proxy all calls to

startDownloading()

and run them in a thread pool. The exact same feature is available through @Asynchronous annotation in EJB.

So we learned a lot about

java.util.concurrent.Future

. Now it's time to admit - this interface is quite limited, especially when compared to other languages. More on that later.

java.util.concurrent.Future Basics的更多相关文章

  1. Java中设置方法执行的超时时间java.util.concurrent.Future

    java.util.concurrent.Future Future代表一个异步计算的结果.它提供了方法来检查是否计算已经完成,还是正在计算而处于等待状态,并且也提供了获取计算结果 方法.当计算完成后 ...

  2. java.util.concurrent包API学习笔记

    newFixedThreadPool 创建一个固定大小的线程池. shutdown():用于关闭启动线程,如果不调用该语句,jvm不会关闭. awaitTermination():用于等待子线程结束, ...

  3. java.util.concurrent 多线程框架

    http://daoger.iteye.com/blog/142485 JDK5中的一个亮点就是将Doug Lea的并发库引入到Java标准库中.Doug Lea确实是一个牛人,能教书,能出书,能编码 ...

  4. jdk8中java.util.concurrent包分析

    并发框架分类 1. Executor相关类 Interfaces. Executor is a simple standardized interface for defining custom th ...

  5. java.util.concurrent包详细分析--转

    原文地址:http://blog.csdn.net/windsunmoon/article/details/36903901 概述 Java.util.concurrent 包含许多线程安全.测试良好 ...

  6. Java 并发工具包 java.util.concurrent 用户指南

    1. java.util.concurrent - Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Ja ...

  7. java.util.concurrent包

    在JavaSE5中,JUC(java.util.concurrent)包出现了 在java.util.concurrent包及其子包中,有了很多好玩的新东西: 1.执行器的概念和线程池的实现.Exec ...

  8. Java并发编程-并发工具包(java.util.concurrent)使用指南(全)

    1. java.util.concurrent - Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Ja ...

  9. java.util.concurrent

    软件包 java.util.concurrent 的描述 在并发编程中很常用的实用工具类.此包包括了几个小的.已标准化的可扩展框架,以及一些提供有用功能的类,没有这些类,这些功能会很难实现或实现起来冗 ...

随机推荐

  1. [Php] Deprecated: Function ereg_replace() is deprecated

    From: http://www.zxyf.net/n6805c18.shtml 这个问题是因为你用的php版本过高. 在php5.3中,正则函数ereg_replace已经废弃,而dedecms还继 ...

  2. scala 日期格式转换

    scala> val format = new java.text.SimpleDateFormat("dd-MM-yyyy") 注意MM必须要大写 format: java ...

  3. GridView如何将分页数据全部导出为EXCEL?

    GRIDVIEW分页状态下将全部数据导出 protected void Button2_Click(object sender, EventArgs e)//按button2将gridview将数据导 ...

  4. php 区分0和空

    能够区分出来的有2,4,6 方法 public function test(){ $test=; if($test==''){ echo '<br />在php中1,0即为空'; //被输 ...

  5. 周期性调度器scheduler_tick

    周期性调度器由中断实现,系统定时产生一个中断,然后启动周期性调度器,周期性调度器执行过程中要关闭中断, 周期性调度器执行完毕后再打开中断(handle_IRQ_event,  IRQF_DISABLE ...

  6. jmeter jdbc request 如何运行多个sql

    database url:jdbc:mysql://127.0.0.1:3306/api?useUnicode=true&allowMultiQueries=true&characte ...

  7. Android 布局学习之——Layout(布局)详解一

    layout(布局)定义了用户界面的可视化结构(visual structure),如Activity的UI,应用窗口的UI. 有两种方式声明layout: 1.在xml文件中声明UI组件. 2.在运 ...

  8. js堆栈与队列简单记忆

    在面向对象的程序设计里,一般都提供了实现队列(queue)和堆栈(stack)的方法,而对于JS来说,我们可以实现数组的相关操作,来实现队列和堆栈的功能,看下面的相关介绍. 一 看一下它们的性质,这种 ...

  9. CSS3与动画有关的属性transition、animation、transform对比

    最近应公司需求,需要用css3做动画,终于把以前一直傻傻分不清楚的三个属性理解了. 索性在这里进行一个简单的对比,加深自己的记忆. 浏览器兼容性 CSS3 transform 属性 Internet ...

  10. android:versionCode和android:versionName 用途(转)

    转自:http://blog.csdn.net/wh_19910525/article/details/8660416 Android的版本可以在androidmainfest.xml中定义,主要有a ...