Java中的Callable和Future

原文地址:http://www.geeksforgeeks.org/callable-future-java/

Callable的用处

在Java中创建线程有两种方法——一种是继承Thread类,另一种是实现Runnable接口。但是Runnable没有的一个特点就是它不能在线程结束的时候返回结果,例如当run()结束了。Java中的Callable接口正好支持这个特征。

Callable vs Runnable

  • 对于Runnable的实现,run()方法也得必须的实现,但是它不能返回任何东西,但是在Callable中,实现call()的话就可以在结束时返回结果。注意不能用Callable创建线程,线程只能用Runnable来创建。
  • 另外的一个不同之处就是call()方法可以抛异常,但是run()不行。

实现Callable必须重载方法签名。

public Object call() throws Exception;

这里是一个Callable例子的代码,它在每0-4秒的延迟间隔会返回一个随机数。

// Java program to illustrate Callable
// to return a random number
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class CallableExample implements Callable {

    public Object call() throws Exception {
        // Create random number generator
        Random generator = new Random();

        Integer randomNumber = generator.nextInt(5);

        // To simulate a heavy computation,
        // we delay the thread for some random time
        Thread.sleep(randomNumber * 1000);

        return randomNumber;
    }
}

Future

当一个call()方法执行完成的时候,结果就必须保存在main线程已知的对象中,这样main线程就可以知道这个线程返回的结果是什么。那么代码在后来是如何保存并获取这个结果的呢?对于这个问题,就可以用Future对象了。考虑一个Future对象得到这个结果——它可能不会立马拿到,但是将来(Future,一旦Callable返回)也会拿到。因此,一个Future实际就是main线程的一个路径,可以对其他线程的进度和结果进行跟踪。想要实现这个接口,有5个方法必须得重载,但是在下面的例子中用了一个具体的库实现,只有几个重要的方法列在了这里。

注意到Callable和Future做的是两种不同的事情——Callable类似于Runnable,它封装了任务并运行在其他的线程上,因此Future是用于从其他线程获取并存储结果。实际上,Future可以跟Runnable做的工作是一样的,这就使得在Executors出现的时候情况就变得更加清晰了。

  • public boolean cancel(boolean mayInterrupt):用于停止任务。如果一个任务没有启动,那就停止它。如果已经启动了,并且mayInterrupt为true,那么就中断这个任务。
  • public Object get() throws InterruptedException, ExecutionException: 用于得到任务的结果。如果任务完成了,它就立即返回结果,否则就等待任务的完成然后返回结果。
  • public boolean isDone():如果一个任务完成了就返回true,否则返回false。

想创建线程,那就需要Runnable,想要得到结果,那就用Future。

Java库中有FutureType具体的类型,它实现了Runnable和Future,同时结合了两边的便捷。

FutureTask对象可以通过它的构造函数和Callable来创建,然后FutureTask将提供给Thread的构造函数来创建一个Thread对象。因此,Callable间接地创建了线程。再一次强调,Callable是不可能直接创建线程的。

这里是用Callable和FutureTask的例子代码:

// Java program to illustrate Callable and FutureTask
// for random number generation
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class CallableExample implements Callable {

    public Object call() throws Exception {
        Random generator = new Random();
        Integer randomNumber = generator.nextInt(5);

        Thread.sleep(randomNumber * 1000);

        return randomNumber;
    }

}

public class CallableFutureTest {
    public static void main(String[] args) throws Exception {

        // FutureTask is a concrete class that
        // implements both Runnable and Future
        FutureTask[] randomNumberTasks = new FutureTask[5];

        for (int i = 0; i < 5; i++) {
            Callable callable = new CallableExample();

            // Create the FutureTask with Callable
            randomNumberTasks[i] = new FutureTask(callable);

            // As it implements Runnable, create Thread
            // with FutureTask
            Thread t = new Thread(randomNumberTasks[i]);
            t.start();
        }

        for (int i = 0; i < 5; i++) {
            // As it implements Future, we can call get()
            System.out.println(randomNumberTasks[i].get());

            // This method blocks till the result is obtained
            // The get method can throw checked exceptions
            // like when it is interrupted. This is the reason
            // for adding the throws clause to main
        }
    }
}

输出:

4
2
3
3
0

启动之后与线程的所有交互都是用实现Future接口的FutureTask对象。因此就没必要保存Thread对象了。利用FutureTask对象,可以取消任务,检查任务是否已经完成并尝试得到结果。

下面是只用Runnable的代码。

// Java program to illustrate Runnable
// for random number generation
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class RunnableExample implements Runnable {
    // Shared object to store result
    private Object result = null;

    public void run() {
        Random generator = new Random();
        Integer randomNumber = generator.nextInt(5);

        // As run cannot throw any Exception
        try {
            Thread.sleep(randomNumber * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Store the return value in result when done
        result = randomNumber;

        // Wake up threads blocked on the get() method
        synchronized (this) {
            notifyAll();
        }
    }

    public synchronized Object get() throws InterruptedException {
        while (result == null)
            wait();

        return result;
    }
}

// Code is almost same as the previous example with a
// few changes made to use Runnable instead of Callable
public class RunnableTest {
    public static void main(String[] args) throws Exception {
        RunnableExample[] randomNumberTasks = new RunnableExample[5];

        for (int i = 0; i < 5; i++) {
            randomNumberTasks[i] = new RunnableExample();
            Thread t = new Thread(randomNumberTasks[i]);
            t.start();
        }

        for (int i = 0; i < 5; i++)
            System.out.println(randomNumberTasks[i].get());
    }
}

输出示例:

0
4
3
1
4
2

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值