详细解读Callable接口及Futrue接口详解

简介: 详细解读Callable接口及Futrue接口详解

目录

Callable接口Futrue接口1.使用Callable和Future的完整示例2.使用Callable和FutureTask的完整示例3.使用Runnable来获取返回结果的实现

回到顶部Callable接口

有两种创建线程的方法-一种是通过创建Thread类,另一种是通过使用Runnable创建线程。但是,Runnable缺少的一项功能是,当线程终止时(即run()完成时),我们无法使线程返回结果。为了支持此功能,Java中提供了Callable接口。

为了实现Runnable,需要实现不返回任何内容的run()方法,而对于Callable,需要实现在完成时返回结果的call()方法。请注意,不能使用Callable创建线程,只能使用Runnable创建线程。

另一个区别是call()方法可以引发异常,而run()则不能。

为实现Callable而必须重写call方法。

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

}

}

回到顶部Futrue接口

当call()方法完成时,结果必须存储在主线程已知的对象中,以便主线程可以知道该线程返回的结果。为此,可以使用Future对象。将Future视为保存结果的对象–它可能暂时不保存结果,但将来会保存(一旦Callable返回)。因此,Future基本上是主线程可以跟踪进度以及其他线程的结果的一种方式。要实现此接口,必须重写5种方法,但是由于下面的示例使用了库中的具体实现,因此这里仅列出了重要的方法。

public boolean cancel(boolean mayInterrupt):用于停止任务。如果尚未启动,它将停止任务。如果已启动,则仅在mayInterrupt为true时才会中断任务。

public Object get()抛出InterruptedException,ExecutionException:用于获取任务的结果。如果任务完成,它将立即返回结果,否则将等待任务完成,然后返回结果。

public boolean isDone():如果任务完成,则返回true,否则返回false

可以看到Callable和Future做两件事-Callable与Runnable类似,因为它封装了要在另一个线程上运行的任务,而Future用于存储从另一个线程获得的结果。实际上,future也可以与Runnable一起使用。

要创建线程,需要Runnable。为了获得结果,需要future。

Java库具有具体的FutureTask类型,该类型实现Runnable和Future,并方便地将两种功能组合在一起。

可以通过为其构造函数提供Callable来创建FutureTask。然后,将FutureTask对象提供给Thread的构造函数以创建Thread对象。因此,间接地使用Callable创建线程。

1.使用Callable和Future的完整示例

package com.example.thread.callable;

import java.util.ArrayList;

import java.util.Date;

import java.util.List;

import java.util.concurrent.;

/

@author: GuanBin

@date: Created in 下午11:19 2019/10/31

*/

public class TestCallable implements Callable {

private int taskNum;

public TestCallable(int taskNum) {

this.taskNum = taskNum;

}

//1,2主要区别是创建线程的方式

public static void main(String【】 args) throws ExecutionException, InterruptedException {

test1();

test2();

}

/

使用Executors.newFixedThreadPool创建线程池

@throws InterruptedException

@throws ExecutionException

/

private static void test1() throws InterruptedException, ExecutionException {

System.out.println("程序开始运行");

Date date1 = new Date();

int taskSize=5;

ExecutorService pool = Executors.newFixedThreadPool(taskSize);

List list = new ArrayList();

for (int i = 0; i < taskSize; i++) {

Callable c = new TestCallable(i);

// 执行任务并获取Future对象

Future f = pool.submit(c);

list.add(f);

}

// 关闭线程池

pool.shutdown();

// 获取所有并发任务的运行结果

for (Future f : list) {

// 从Future对象上获取任务的返回值,并输出到控制台

System.out.println("]>" + f.get().toString()); //OPTION + return 抛异常

}

Date date2 = new Date();

System.out.println("程序结束运行,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】");

}

/

线程直接使用new Thread来创建

@throws ExecutionException

@throws InterruptedException

/

private static void test2() throws ExecutionException, InterruptedException {

System.out.println("程序开始运行");

Date date1 = new Date();

int taskSize=5;

FutureTask【】 randomNumberTasks = new FutureTask【5】;

List list = new ArrayList();

for (int i = 0; i < randomNumberTasks.length; i++) {

Callable c = new TestCallable(i);

// 执行任务并获取Future对象

randomNumberTasks【i】= new FutureTask(c);

Thread t = new Thread(randomNumberTasks【i】);

t.start();

}

// 获取所有并发任务的运行结果

for (Future f : randomNumberTasks) {

// 从Future对象上获取任务的返回值,并输

System.out.println("]>" + f.get().toString()); //OPTION + return 抛异常

}

Date date2 = new Date();

System.out.println("程序结束运行,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】");

}

/

call方法的实现,主要用于执行线程的具体实现,并返回结果

@return

@throws Exception

/

@Override

public Object call() throws Exception {

System.out.println("]>" + taskNum + "任务启动");

Date dateTmp1 = new Date();

Thread.sleep(1000);

Date dateTmp2 = new Date();

long time = dateTmp2.getTime() - dateTmp1.getTime();

System.out.println("]>" + taskNum + "任务终止");

return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";

}

}

输出

程序开始运行

]>0任务启动

程序结束运行,程序运行时间【1007毫秒】

Process finished with exit //代码效果参考:http://www.zidongmutanji.com/bxxx/177472.html

code 0

2.使用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++)

//代码效果参考:http://www.zidongmutanji.com/bxxx/563752.html

{

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

}

}

}

启动线程后,与线程的所有交互都使用FutureTask,因为它实现了Future接口。因此,不需要存储Thread对象。使用FutureTask对象,还可以取消任务,检查任务是否完成或尝试获取结果。

3.使用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());

}

}

作者:guanbin —— 纵码万里千山

出处:

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

相关文章
|
5月前
|
存储 Java
高并发编程之多线程锁和Callable&Future 接口
高并发编程之多线程锁和Callable&Future 接口
74 1
|
5月前
|
Java
JAVA JUC Callable 接口
【1月更文挑战第5天】JAVA JUC Callable 接口
|
17天前
|
Java C++
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
26 0
|
5月前
|
Java 程序员
Java多线程基础-16:简述Java并发编程JUC中的Callable接口
Callable接口是Java中用于描述带有返回值任务的接口,与Runnable相对,后者无返回值。Callable的call()方法用于执行具体任务并返回结果。
78 0
|
5月前
|
Java
Java并发编程:理解并使用Future和Callable接口
【2月更文挑战第25天】 在Java中,多线程编程是一个重要的概念,它允许我们同时执行多个任务。然而,有时候我们需要等待一个或多个线程完成,然后才能继续执行其他任务。这就需要使用到Future和Callable接口。本文将深入探讨这两个接口的用法,以及它们如何帮助我们更好地管理多线程。
|
5月前
|
Java
创建线程的三种方式:继承Thread、Runnable 接口、Callable 接口
创建线程的三种方式:继承Thread、Runnable 接口、Callable 接口
|
5月前
|
Java 程序员
【JavaEE初阶】 Callable 接口
【JavaEE初阶】 Callable 接口
|
5月前
|
Java
多线程创建方式三 - 实现Callable接口
多线程创建方式三 - 实现Callable接口
44 1
|
5月前
|
安全 Java C++
多线程之Callable接口、ReentrantLock、信号量 Semaphore以及CountDownLatch
多线程之Callable接口、ReentrantLock、信号量 Semaphore以及CountDownLatch
|
2月前
|
并行计算 Java 大数据
Callable和Future
Callable和Future