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使用的更多相关文章

  1. JAVA线程池中的Callable和Future

    import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.Completio ...

  2. java多线程Future和Callable类的解释与使用

    一,描写叙述 ​在多线程下编程的时候.大家可能会遇到一种需求,就是我想在我开启的线程都结束时,同一时候获取每一个线程中返回的数据然后再做统一处理,在这种需求下,Future与Callable的组合就派 ...

  3. java 线程Thread 技术--1.5 Future与Callable

    Callable: 从官方文档说起: 通过实现callable 的called 方法可以使一个任务可以返回一个结果以及可能抛出一个异常: callable 与runnable 是相似的,可以被其他线程 ...

  4. java并发编程-Executor框架 + Callable + Future

    from: https://www.cnblogs.com/shipengzhi/articles/2067154.html import java.util.concurrent.*; public ...

  5. java多线程获取返回结果--Callable和Future示例

    package test.guyezhai.thread; import java.util.ArrayList; import java.util.Date; import java.util.Li ...

  6. Java中的Runnable、Callable、Future、FutureTask的区别

    本文转载自:http://blog.csdn.net/bboyfeiyu/article/details/24851847 Runnable 其中Runnable应该是我们最熟悉的接口,它只有一个ru ...

  7. Java中的Runnable、Callable、Future、FutureTask的区别与示例

    Java中存在Runnable.Callable.Future.FutureTask这几个与线程相关的类或者接口,在Java中也是比较重要的几个概念,我们通过下面的简单示例来了解一下它们的作用于区别. ...

  8. Java并发编程 - Runnbale、Future、Callable 你不知道的那点事(二)

    Java并发编程 - Runnbale.Future.Callable 你不知道的那点事(一)大致说明了一下 Runnable.Future.Callable 接口之间的关系,也说明了一些内部常用的方 ...

  9. Java并发编程 - Runnbale、Future、Callable 你不知道的那点事(一)

    从事Java开发已经快两年了,都说Java并发编程比较难,比较重要,关键面试必问,但是在我的日常开发过程中,还真的没有过多的用到过并发编程:这不疫情嘛,周末不能瞎逛,就看看师傅们常说的 Runnabl ...

随机推荐

  1. centosflask+uWSGI+nginx部署

    centosflask+uWSGI+nginx部署 1.      概念 Flask自带webserver--Werkzeug,可以搭建服务,运行网站.但在开发时,一般会用专业的--uWSGI. 另外 ...

  2. idea整合scala

    scala依赖java环境,首先下载jdk1.8 64位 1.windows安装scala环境 下载scala环境,执行 进入doc窗口输入scala -version查看scala版本号,出现版本号 ...

  3. Catalyst 3850 升级-1

    Cisco Catalyst 3850交换机使用Cisco IOS XE软件. Cisco IOS XE软件是一个包含一组包文件的一个集合. 我们可以使用以下两种模式之一在Cisco Catalyst ...

  4. Cisco TrustSec(理解)

    1.Cisco TrustSec的限制当指定了无效的设备ID时,受保护的访问凭据(Protected access credential,PAC)设置将失败并保持挂起状态. 即使在清除PAC并配置正确 ...

  5. ANSYS单元应用简介1

    目录 1. LINK单元 2. BEAM单元 3. PLANE单元 4. SHELL单元 5. SOLIDE单元 6. COMBIN单元 ANSYS中的单元针对不同的应用对象,有着不同的选择方法,下面 ...

  6. 软件版本 Alpha、Beta、Rc

    软件版本的周期 α.β.γ 表示软件测试中的三个阶段 α :第一阶段,内部测试使用 β: 第二阶段,消除了大部分不完善的地方,仍可能存在漏洞,一般提供给特定的用户使用 γ: 第三阶段,产品成熟,个别地 ...

  7. Atcoder Grand Contest 039B(思维,BFS)

    #define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace std;int col[207],s[207],n;c ...

  8. 简单bat脚本

    hwf.bat: set GAP_HOME=%~dp0\.. ::copy "%JAVA_HOME%\bin\javaw.exe" "%JAVA_HOME%\bin\HW ...

  9. python requirements.txt批量下载安装离线

    有些情况下我们需要下载N个第三方包,或者下载的包依赖其它包,一个个下载非常浪费时间.这时我们可以通过如下两种方式的命令批量下载. 方式1 pip download -d /tmp/packagesdi ...

  10. 第一周之Hadoop学习(一)

    首先根据网上的教程得搭建一个linux的环境,所以第一部分是下载虚拟机的过程. 参考博客:https://blog.csdn.net/hliq5399/article/details/78193113 ...