Callable and FutureTask

2024-04-22 03:04
文章标签 callable futuretask

本文主要是介绍Callable and FutureTask,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Callable

由关系图可知,Callable和Runnable一样,也是一个函数式接口,可以使用Lambda表达式

与之不同的是,其内部的call()方法可以抛出异常且能return一个返回值

 Callable<Object> callable = new Callable() {@Overridepublic Object call() throws Exception {System.out.println("执行call方法");return null;}};

FutureTask

FutureTask构造方法源码:public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW;       // ensure visibility of callable}public FutureTask(Runnable runnable, V result) {this.callable = Executors.callable(runnable, result);this.state = NEW;       // ensure visibility of callable}

Future接口方法

 //mayInterruptIfRunning:是否取消正在执行但还有执行完毕的任务 //true:取消任务 返回true//false:让任务执行完毕 返回falseboolean cancel(boolean mayInterruptIfRunning);//任务是否被取消boolean isCancelled();//任务是否完成 //完成可能是由于正常终止、异常或取消 --- 在所有这些情况下,此方法将返回 trueboolean isDone();//得到任务返回值,如果未执行的话会阻塞等待V get() throws InterruptedException, ExecutionException;//设置最大阻塞时间,如果超过最大阻塞时间后还是没有执行完任务,抛出TimeOutExceptionV get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;

根据上方关系图我们可知

FutureTask可以包装Runnable/Callable对象-----构造方法

FutureTask实现了Runnable接口 ,故其可以作为Runnable被线程执行

notice:线程执行的是FutureTask类包装的Callable对象下的call()方法

public static void main(String[] args) throws ExecutionException, InterruptedException {//使用Callable进行1-100相加数和Callable<Long> callable = new Callable<Long>() {@Overridepublic Long call() throws Exception {System.out.println("开始执行子线程相加内容");long sum = 0;for(int i = 1; i <= 100; i++){sum += i;}return sum;}};FutureTask<Long> futureTask = new FutureTask<>(callable);Thread t = new Thread(futureTask);//真正执行call方法的是线程 所以必须要启动线程后 call方法才会执行//t.start();//相当于t.join操作System.out.println("futureTask.get()得到call方法的函数返回值:"+futureTask.get()); //如果没有call方法内容没有执行完 get方法会一直阻塞
}

此时没有执行t.start操作,futureTask.get()方法就会一直阻塞

反之执行t.start;


 
  //使用Callable进行1-100相加数和Callable<Long> callable = new Callable<Long>() {@Overridepublic Long call() throws Exception {Thread.sleep(3000);System.out.println("开始执行子线程相加内容");long sum = 0;for(int i = 1; i <= 100; i++){sum += i;}return sum;}};FutureTask<Long> futureTask = new FutureTask<>(callable);Thread t = new Thread(futureTask);//真正执行call方法的是线程 所以必须要启动线程后 call方法才会执行t.start();long begin = System.currentTimeMillis();//相当于t.join操作System.out.println("futureTask.get()得到call方法的函数返回值:"+futureTask.get()); //如果没有call方法内容没有执行完 get方法会一直阻塞long end = System.currentTimeMillis();System.out.println("阻塞时间:"+ (end -begin));}

上述代码中,我们在call方法中休眠了三秒,由于当get方法任务没有执行完时,就会阻塞,故主线程被三秒,所以get()操作类似于join方法


get():

我们知道,当线程在休眠时被终止时,会触发sleep内部异常,在Runnable中,触发异常后并不会终止进程,而是将线程提前唤醒,且将终止标志位重新设置为false,后续的操作由程序员的代码决定 

public static void main(String[] args) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {for(int i = 0; i < 3; i++){System.out.println("Hello World");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();System.out.println("触发skeep interrupted异常 后续执行操作由我决定");}}}});t1.start();t1.interrupt();System.out.println("线程是否被终止:"+t1.isInterrupted());}

即使触发了异常,但还是继续完成了runnable中的run方法


但在Callable中,如果线程被休眠时被唤醒,FutureTask.get()方法就会直接报错且退出程序

public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<String> callable = new Callable<String>() {@Overridepublic String call() throws Exception {System.out.println("你好");Thread.sleep(1000);return "我要报错拉";}};FutureTask task = new FutureTask(callable);Thread t = new Thread(task);t.start();t.interrupt();//非正常终止 --- 休眠时终止System.out.println("isDone:"+task.isDone());System.out.println(task.get());}


但如果仅仅是启动线程(没有FutureTask.get()操作),那么不会报错,但会直接终止线程

 public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<String> callable = new Callable<String>() {@Overridepublic String call() throws Exception {for(int i = 0; i < 3; i++){System.out.println("你好");Thread.sleep(1000);}return "我要报错拉";}};FutureTask task = new FutureTask(callable);Thread t = new Thread(task);t.start();t.interrupt();//非正常终止 --- 休眠时终止System.out.println("isDone:"+task.isDone());}


超时get():
 public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {//超时get方法Callable<String> callable = new Callable<String>() {@Overridepublic String call() throws Exception {Thread.sleep(2000);System.out.println("任务继续执行");return "ok";}};FutureTask futureTask = new FutureTask(callable);Thread t = new Thread(futureTask);t.start();//若超出时间 报TimeoutException异常 call方法中的内容继续进行  //无法取到call方法中的返回值了System.out.println(futureTask.get(1, TimeUnit.SECONDS));}

.

超时后call方法中的任务还是会继续进行,但无法通过get方法获得call方法的返回值了


cancel():
public static void main(String[] args) {Callable<Integer> callable = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum = 0;for(int i = 0; i <= 10; i++){sum += i;}return sum;}};FutureTask<Integer> futureTask = new FutureTask<>(callable);Thread t = new Thread(futureTask);t.start();//取消任务  参数mayInterruptIfRunning是否取消正在运行的任务  其内部实际上还是通过interrupt方法System.out.println("cancel:"+futureTask.cancel(true));//任务是否被取消System.out.println("isCancelled:"+futureTask.isCancelled());//任务是否执行完成//如果此任务已完成,则返回 true。完成可能是由于正常终止、异常或取消 -- 在所有这些情况下,此方法将返回 trueSystem.out.println("isDone:"+futureTask.isDone());}


 //取消任务  参数mayInterruptIfRunning是否取消正在运行的任务  其内部实际上还是通过interrupt方法System.out.println("cancel:"+futureTask.cancel(true));//在取消任务后 调用get方法 此时不能返回call方法返回值 且会抛出异常 退出程序System.out.println("after cancel:"+ futureTask.get());


使用线程池执行Callable
//利用线程池执行public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService service = Executors.newFixedThreadPool(10);//execute Runnable command//submit Future<V> future//这里是Callable 只能使用submit Runnable/Callable都可以 返回值是Future<?> / 不能使用execute:RunnableFuture<String> future = service.submit(new Callable<String>() {@Overridepublic String call() throws Exception {return "Hello World";}});System.out.println(future.get());service.shutdown();}

这篇关于Callable and FutureTask的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/924678

相关文章

Callable 和Future

在Java5之前,线程是没有返回值的,常常为了“有”返回值,破费周折,而且代码很不好写。或者干脆绕过这道坎,走别的路了。 现在Java终于有可返回值的任务(也可以叫做线程)了。  可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。 执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callabl

Callable及Future

1.Runnable Runnable是个接口,使用很简单: 1. 实现该接口并重写run方法 2. 利用该类的对象创建线程 3. 线程启动时就会自动调用该对象的run方法 通常在开发中结合ExecutorService使用,将任务的提交与任务的执行解耦开,同时也能更好地利用Executor提供的各种特性 ExecutorService executor

java.util.concurrent中的Callable,Future

Java中存在Runnable、Callable、Future、FutureTask这几个与线程相关的类或者接口,在Java中也是比较重要的几个概念,我们通过下面的简单示例来了解一下它们的作用于区别。 Runnable 其中Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Th

多线程(callable+futureTask)去组装数据,并批量入库

商城项目,收货地址会用到4级地址(省,市,县,镇),我们只用到了特定城市的。 但是我想通过京东的接口把全部的数据拿出来。于是就有 ------多线程(callable+futureTask)去组装数据。 ---------------------------     先贴下controller的代码: package com.truelore.xunjia.wssc.test.c

Pandas报错AttributeError: Cannot access callable attribute 'sort_values' of 'DataFrameGroupBy' objects

完整报错如下: AttributeError: Cannot access callable attribute 'sort_values' of 'DataFrameGroupBy' objects, try using the 'apply' method 报错代码如下: import pandas as pddata = pf.read_csv('test.csv',header =

学习分享-Callable 和 Runnable 任务

前言 顺带回顾学习一下Callable 或 Runnable 任务 Callable 和 Runnable 任务 Callable 和 Runnable 是 Java 中用于定义任务的接口,它们主要用于并发编程,允许任务在独立的线程中运行。 Runnable 任务 Runnable 是一个函数式接口,只包含一个 run() 方法。它不返回任何结果,也不能抛出检查型异常。Runnable

java 实现线程的三种方式 Thread 、Runnable、 Callable Future

继承Thread类,重写run方法 例如: /*** 实现线程方式一 继承Thread类* * @author wbw* */public class MyThread1 extends Thread {@Overridepublic void run() {try {for (int i = 0; i < 10; i++) {System.out.println("Hello" + i

【已解决】Python错误:TypeError: ‘int‘ object is not callable的解决办法

😎 作者介绍:我是程序员洲洲,一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 🤓 同时欢迎大家关注其他专栏,我将分享Web前后端开发、人工智能、机器学习、深度学习从0到1系列文章。 🌼 同时洲洲已经建立了程序员技术交流群,如果您感兴趣,可以私信我加入社群,可以直接vx联系(文末有名片)v:bdizztt 🖥 随时欢迎您跟我沟通

学习分享-FutureTask

前言 今天再改简历的时候回顾了之前实习用到的FutureTask,借此来回顾一下相关知识。 FutureTask 介绍 FutureTask 是 Java 并发包(java.util.concurrent)中的一个类,用于封装异步任务。它实现了 RunnableFuture 接口,而 RunnableFuture 接口继承了 Runnable 和 Future 接口。因此,FutureTas

php之 Callable 可调用对象

近期在读laravel源码,感觉收获蛮多。php官方文档果然是最佳学习教程。 一些函数如 call_user_func() 或 usort() 可以接受用户自定义的回调函数作为参数。 回调函数不止可以是简单函数,还可以是对象的方法,包括静态类方法。(补充 可调用对象包括 带有___invoke方法类的对象) 传递 一个已实例化的 object 的方法被作为 array 传递,下标