1. Runnable接口的限制

JDK提供了ExecutorService接口表示线程池,可以通过submit提交一个任务。

    ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(task);

但这里的task有个问题,因为继承制Runnable,如果希望返回一个结果,只能用result来表示,这样主线程获取结果,就很不方便。

class Task implements Runnable{
public String result; //只能将结果保存到result,再去读取
public void run(){
this.result = longTimeCalculation();
}
}

因此JDK又提供了一个Callable接口。

2. Callable接口

相比Runnable接口,Callable接口多了一个返回值。这样我们就可以用submit()方法把一个Callable的task提交给executor,异步执行。

不需要返回结果 需要返回结果
Runnable Callable

当我们使用Callable接口时候,我们需要实现一个泛型接口。例如我们期望返回值是一个String,我们就写implements Callable,并覆写call()方法。
```#java
class Task implements Callable{
public String call() throws Exception{
return longTimeCalculation();
}
}
```
## 3. Future
如果获得异步执行的结果呢?
```#java
Callable task = new Task();
ExecutorService executor = Executors.newFixedThreadPool(4);
Future future = exector.submit(task);
String result = future.get(); //可能阻塞
```
当我们提交一个Callable任务以后,会同时获得一个Future对象。
接着在主线程的某个时刻调用Future对象的get()方法就可以获得异步执行的结果:
* 在调用get()方法的时候,如果异步任务已经完成,就直接获得结果;
* 如果异步任务未完成,那么get()方法就会阻塞,直到任务完成以后,返回结果。

Future接口:表示一个未来可能会返回的结果

    get():返回一个异步执行的结果
get(long timeout, TimeUnit unit):指定一个最长的等待时间
cancel(boolean mayInterruptIfRunning):中断一个异步任务的执行
isDone():判断当前的异步任务是否已经完成

4. 示例

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; class DownloadTask implements Callable<String> {
String url;
public DownloadTask(String url){
this.url = url;
}
public String call() throws Exception {
System.out.println("start download " + url + "...");
URLConnection conn = new URL(this.url).openConnection();
conn.connect();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))){ String s = null;
StringBuilder sb = new StringBuilder();
while ((s = reader.readLine()) != null) {
sb.append(s).append("\n");
}
return sb.toString();
} } }
public class Main{
public static void main(String[] args) throws Exception{
ExecutorService executor = Executors.newFixedThreadPool(3);
DownloadTask task = new DownloadTask("https://www.sina.com.cn");
Future<String> future = executor.submit(task);
String html = future.get();
System.out.println(html);
executor.shutdown();
}
}

5.总结:

  • 需要返回结果,使用Callable;不需要返回结果,使用Runnable
  • 提交Callable任务,可以获得一个Future对象
  • 可以用Future在将来某个时刻获得结果

廖雪峰Java11多线程编程-3高级concurrent包-7Future的更多相关文章

  1. 廖雪峰Java11多线程编程-3高级concurrent包-5Atomic

    Atomic java.util.concurrent.atomic提供了一组原子类型操作: 如AtomicInteger提供了 int addAndGet(int delta) int increm ...

  2. 廖雪峰Java11多线程编程-3高级concurrent包-4Concurrent集合

    Concurrent 用ReentrantLock+Condition实现Blocking Queue. Blocking Queue:当一个线程调用getTask()时,该方法内部可能让给线程进入等 ...

  3. 廖雪峰Java11多线程编程-3高级concurrent包-1ReentrantLock

    线程同步: 是因为多线程读写竞争资源需要同步 Java语言提供了synchronized/wait/notify来实现同步 编写多线程同步很困难 所以Java提供了java.util.concurre ...

  4. 廖雪峰Java11多线程编程-3高级concurrent包-6ExecutorService

    Java语言内置多线程支持: 创建线程需要操作系统资源(线程资源,栈空间) 频繁创建和销毁线程需要消耗大量时间 如果可以复用一个线程 线程池: 线程池维护若干个线程,处于等待状态 如果有新任务,就分配 ...

  5. 廖雪峰Java11多线程编程-3高级concurrent包-9Fork_Join

    线程池可以高效执行大量小任务: Fork/Join线程池可以执行一种特殊的任务: 把一个大任务拆成多个小任务并行执行 Fork/Join是在JDK 1.7引入的 示例:计算一个大数组的和 Fork/J ...

  6. 廖雪峰Java11多线程编程-3高级concurrent包-8CompletableFuture

    使用Future可以获得异步执行结果 Future<String> future = executor.submit(task); String result = future.get() ...

  7. 廖雪峰Java11多线程编程-3高级concurrent包-3Condition

    Condition实现等待和唤醒线程 java.util.locks.ReentrantLock用于替代synchronized加锁 synchronized可以使用wait和notify实现在条件不 ...

  8. 廖雪峰Java11多线程编程-3高级concurrent包-2ReadWriteLock

    ReentrantLock保证单一线程执行 ReentrantLock保证了只有一个线程可以执行临界区代码: 临界区代码:任何时候只有1个线程可以执行的代码块. 临界区指的是一个访问共用资源(例如:共 ...

  9. 廖雪峰Java11多线程编程-2线程同步-3死锁

    1.线程锁可以嵌套 在多线程编程中,要执行synchronized块: 必须首先获得指定对象的锁 Java的线程锁是可重入的锁.对同一个对象,同一个线程,可以多次获取他的锁,即同一把锁可以嵌套.如以下 ...

随机推荐

  1. Linux_磁盘分区、挂载、查看

    一.挂载 1.查看设备的挂载情况 lsblk或lsblk -f 2.挂载 需求 :给我们的Linux系统增加一个新的硬盘,并且挂载到/home/newdisk 说明:我们以增加一块硬盘为例来熟悉一下磁 ...

  2. LOJ #113. 最大异或和 (线性基)

    题目链接:#113. 最大异或和 题目描述 这是一道模板题. 给由 \(n\) 个数组成的一个可重集 \(S\),每次给定一个数 \(k\),求一个集合 \(T \subseteq S\),使得集合 ...

  3. [17]APUE:线程

    通常情况下,线程模型的并发性能优于进程模型,但不总是这样 线程的优势: 线程的创建.销毁及上下文切换代价比进程低 某些情况下,使用线程可以简化逻辑,避免异步编程的复杂性 同一进程内所有线程共享全局内存 ...

  4. 【POJ】3268 Silver Cow Party

    题目链接:http://poj.org/problem?id=3268 题意 :有N头奶牛,M条单向路.X奶牛开party,其他奶牛要去它那里.每头奶牛去完X那里还要返回.去回都是走的最短路.现在问这 ...

  5. css元素垂直居中

    一.碎碎念:啊啊啊,原谅我只能起一个酱紫微大众微俗气的标题,因为实在没有什么能比这样表达的更清楚直观了呢! 二.没有知识储备,直接上示例: 1.思路:给父元素添加display: table属性:给子 ...

  6. Ros node启动与关闭

    1. ros运行单位: Ros程序运行的单位是ros node. 2. ros 节点的启动: (1)初始化ros节点:通过调用ros::init()接口实现:可以通过参数指定默认节点名字,之所以是默认 ...

  7. Vue+Iview+Node 项目结构和配置

    1.项目调整后的目录 api:数据接口定义 assets:静态文件 components:组件  config:项目相关配置  driective:指令   router:路由   store:状态管 ...

  8. python 毫秒时间戳转日期

    import time import datetime timestamp = 1570774556514 # 转换成localtime time_local = time.localtime(tim ...

  9. golang模块viper读取配置文件

    一.介绍 Viper是一个方便Go语言应用程序处理配置信息的库.它可以处理多种格式的配置.它支持的特性: 设置默认值 从JSON.TOML.YAML.HCL和Java properties文件中读取配 ...

  10. Mysq 列中存储json格式根据key取value

    SELECT DISTINCT (SUBSTRING_INDEX( REPLACE ( 列名称, CONCAT( SUBSTRING_INDEX( 列名称, '"key名称":', ...