Java中的Callable和Future

作者: Arvin Chen 分类: Java 来源: Break易站(www.breakyizhan.com)

先决条件:线程多线程

Java中的Callable

有两种创建线程的方法 - 一种是通过扩展Thread类,另一种是通过创建一个带有Runnable的线程。但是,Runnable中缺少的一个特性是,当终止时,即run()完成时,我们无法生成线程返回结果。为了支持此功能,Callable接口存在于Java中。

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;
    }
}

Java中的Future

当call()方法完成时,answer必须存储在主线程已知的对象中,以便主线程可以知道线程返回的结果。程序将如何存储并在以后获得此结果?为此,可以使用Future对象。将Future视为一个拥有结果的对象 - 它现在可能无法保持它,但它将来会这样做(一旦Callable返回)。因此,Future基本上是主线程可以跟踪其他线程的进度和结果的一种方式。要实现此接口,必须重写5个方法,但如下例所示,使用库中的具体实现,此处仅列出了重要的方法。

观察Callable和Future做两件事 - Callable类似于Runnable,因为它封装了一个意图在另一个线程上运行的任务,而Future用于存储从不同线程获得的结果。事实上,Future也可以与Runnable一起使用,当执行者进入画面时,这将变得清晰。

  • public boolean cancel(boolean mayInterrupt):用于停止任务。如果任务尚未启动,它将停止该任务。如果已启动,则仅当mayInterrupt为true时才会中断任务。
  • public Object get()throws InterruptedException,ExecutionException:用于获取任务的结果。如果任务完成,则立即返回结果,否则等待任务完成,然后返回结果。
  • public boolean isDone():如果任务完成则返回true,否则返回false

要创建线程,需要Runnable。要获得结果,需要Future。

Java库具有FutureTask的具体类型,它实现了Runnable和Future,方便地结合了两个功能。
可以通过为其构造函数提供Callable来创建FutureTask。然后将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

在线程启动后与线程的所有交互都使用FutureTask对象,因为它实现了Future接口。因此,不需要存储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
  •   本文标题:Java中的Callable和Future - Break易站
    转载请保留页面地址:https://www.breakyizhan.com/java/4980.html
    扫描二维码添加微信 
  • ,领取淘宝优惠券,淘宝购物更优惠。现在添加微信,还可以领取机械键盘优惠券!添加微信后,分享淘宝选中的机械键盘给淘宝机器人即可领取!
    支持我们,就用微信淘宝!

    发表笔记

    电子邮件地址不会被公开。 必填项已用*标注

    更多阅读