java并发之Future与Callable使用
java并发之Future与Callable使用
这篇文章需要大家知道线程、线程池的知识,尤其是线程池。
有的时候我们要获取线程的执行结果,这个时候就需要用到Callable、Future、FutureTask了
先看下Future、Callable接口、RunnableFuture、FutureTask。
Future
Future是一个接口,能够取消任务、获取任务取消状态、获取结果。
package java.util.concurrent;
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
/**
* Returns {@code true} if this task completed.
*
* Completion may be due to normal termination, an exception, or
* cancellation -- in all of these cases, this method will return
* {@code true}.
*
* @return {@code true} if this task completed
*/
boolean isDone();
/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
*/
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
Callable
Callable只有一个功能就是获取结果的V call()。
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
FutureTask
FutureTask是一个实现类,它继承了RunnableFuture,而接口RunnableFuture继承了接口Runable,Future。
因此FutureTask可以通过new Thread(FutureTask task)这样的方式来创建线程。
public class FutureTask<V> implements RunnableFuture<V>
RunnableFuture
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
通过Future创建线程
获取线程的执行结果,最重要就是FutureTask调用。下面的例子是通过线程池来执行线程,并获取结果 。
1.创建实现Callable接口的类Task,就是返回数字和
2.创建线程池ThreadPoolExecutor,新建Task实例
3.线程池ThreadPoolExecutor执行pool.submit(task)
4.返回了Future result
5.调用Future的get()获取结果
难点是在pool.submit(task)。
package com.java.javabase.thread.future;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author
*/
@Slf4j
public class FutureTest {
public static void main(String[] args) {
//ExecutorService pool = Executors.newCachedThreadPool();
ThreadPoolExecutor pool =new ThreadPoolExecutor(1,1,0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(1));
Task task =new Task();
Future<Integer> result=pool.submit(task);
/*
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
*/
pool.shutdown();
try {
log.info("sum {}",result.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
static class Task implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
return sum;
}
}
}
线程池获取结果流程说明
ThreadPoolExecutor.submit方法中执行void execute(Runnable command);
如果了解线程池就应该知道这个方法是能够让command的run方法执行的。实现接口 RunnableFuture的
FutureTask的run方法最后返回线程结果的关键
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
ThreadPoolExecutor.execute方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
FutureTask构造器
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
FutureTask的run方法
我们创建FutureTask的时候,传入了实现Callable接口的实现类Task,而run()方法中调用了result = c.call();
也就是说FutureTask调用了Callable接口的实现类Task的call方法获取结果,并保存,然后通过对外的get()方法返回。
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
通过FutureTask创建线程
值得注意的就是获取结果的方式,创建FutureTask,也只能通过FutureTask对象get到结果。
pool.submit(futureTask)返回的Future调用get()返回的是null!
package com.java.javabase.thread.future;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author
*/
@Slf4j
public class FutureTaskTest {
public static void main(String[] args) {
//ExecutorService pool = Executors.newCachedThreadPool();
ThreadPoolExecutor pool =new ThreadPoolExecutor(1,1,0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(1));
Task task =new Task();
FutureTask<Integer> futureTask=new FutureTask<Integer>(task);
//Future<?> result =pool.submit(futureTask);
pool.submit(futureTask);
pool.shutdown();
try {
log.info("sum {}",futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Task t2=new Task();
FutureTask<Integer> futureTask2=new FutureTask<Integer>(t2);
new Thread(futureTask2).start();
try {
log.info("sum 2 {}",futureTask2.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
static class Task implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
return sum;
}
}
}
只能通过FutureTask对象get到结果的原因
我就简单强调一点下面的:ftask与task的区别就是获取结果不一致的原因
ftask的run方法调用了对象task的run方法,ftask的get()返回的是null,而实际我们看到自己创建的task的run方法才能返回结果
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
java并发之Future与Callable使用的更多相关文章
- JAVA线程池中的Callable和Future
import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.Completio ...
- java多线程Future和Callable类的解释与使用
一,描写叙述 在多线程下编程的时候.大家可能会遇到一种需求,就是我想在我开启的线程都结束时,同一时候获取每一个线程中返回的数据然后再做统一处理,在这种需求下,Future与Callable的组合就派 ...
- java 线程Thread 技术--1.5 Future与Callable
Callable: 从官方文档说起: 通过实现callable 的called 方法可以使一个任务可以返回一个结果以及可能抛出一个异常: callable 与runnable 是相似的,可以被其他线程 ...
- java并发编程-Executor框架 + Callable + Future
from: https://www.cnblogs.com/shipengzhi/articles/2067154.html import java.util.concurrent.*; public ...
- java多线程获取返回结果--Callable和Future示例
package test.guyezhai.thread; import java.util.ArrayList; import java.util.Date; import java.util.Li ...
- Java中的Runnable、Callable、Future、FutureTask的区别
本文转载自:http://blog.csdn.net/bboyfeiyu/article/details/24851847 Runnable 其中Runnable应该是我们最熟悉的接口,它只有一个ru ...
- Java中的Runnable、Callable、Future、FutureTask的区别与示例
Java中存在Runnable.Callable.Future.FutureTask这几个与线程相关的类或者接口,在Java中也是比较重要的几个概念,我们通过下面的简单示例来了解一下它们的作用于区别. ...
- Java并发编程 - Runnbale、Future、Callable 你不知道的那点事(二)
Java并发编程 - Runnbale.Future.Callable 你不知道的那点事(一)大致说明了一下 Runnable.Future.Callable 接口之间的关系,也说明了一些内部常用的方 ...
- Java并发编程 - Runnbale、Future、Callable 你不知道的那点事(一)
从事Java开发已经快两年了,都说Java并发编程比较难,比较重要,关键面试必问,但是在我的日常开发过程中,还真的没有过多的用到过并发编程:这不疫情嘛,周末不能瞎逛,就看看师傅们常说的 Runnabl ...
随机推荐
- http的长连接和短连接(史上最通俗!)
1.以前的误解 很久之前就听说过长连接的说法,而且还知道HTTP1.0协议不支持长连接,从HTTP1.1协议以后,连接默认都是长连接.但终究觉得对于长连接一直懵懵懂懂的,有种抓不到关键点的感觉. 今天 ...
- Spring 的 Bean 生命周期,11 张高清流程图及代码,深度解析
在网上已经有跟多Bean的生命周期的博客,但是很多都是基于比较老的版本了,最近吧整个流程化成了一个流程图.待会儿使用流程图,说明以及代码的形式来说明整个声明周期的流程.注意因为代码比较多,这里的流程图 ...
- dwz中的(tree)树形菜单的默认收缩
做网站后台时,为了方便管理,可能会用到dwz中的树形菜单,如下: 树形菜单的收缩有默认属性值,可以对其进行一定的初始设定: DWZ的树结构是按<ul>,<li>的嵌套格式构成, ...
- pip配置永久国内源
1.windows配置方式: (1)打开文件资源管理器 --------在地址栏中输入 %appdata% (2)手动创建一个文件夹叫做 pip (3)在pip的文件夹里面新建一个文件 pip.ini ...
- 2019牛客暑期多校训练营(第七场)A String (字符串的最小表示)
思路 这题思路如果是递归的话,应该是比较正确的.但是实际上只用切割两次就可以了. 先把原串从后向前切割一次,再把每一部分切割一次. 切两次的思路实际上是有漏洞的. 递归的思路,终点是,如果串长为1,或 ...
- 吴裕雄--天生自然Numpy库学习笔记:NumPy 算术函数
NumPy 算术函数包含简单的加减乘除: add(),subtract(),multiply() 和 divide(). 需要注意的是数组必须具有相同的形状或符合数组广播规则. import nump ...
- Nexus-VDC(Virtual Device Context)
VDC实际上是将一台物理的Nexus7K设备虚拟为多个逻辑的VDC设备,该术语叫做VDC(Virtual Device Context),该虚拟技术实际上是在一个物理设备架构和内核上运行多个VDC,已 ...
- Mapgis地图颜色配置(专题图配置)----对比Arcgis根据属性配置图斑颜色
对于大多数arcgis用户来说,根据属性配置图斑颜色对于大家来说应该并不陌生.本文将就arcgis图斑颜色设置与mapgis做出比对,为大家提供更为绚丽的地图配色. Arcgis颜色配置方案 右 ...
- 如何用 pycharm 调试 airflow
airflow 和 pycharm 相关基础知识请看其他博客 我们在使用 airflow的 dag时. 每次写完不知道对不对的,总不能到页面环境中跑一下,等到报错再调试吧.这是很让人恼火的事情 这里我 ...
- HashMap中推荐使用entrySet方式遍历Map类集合KV而不是keySet方式遍历
我们先来做一个测试 public class HashMapTest { private HashMap<String, String> map = new HashMap<> ...