多线程 - Callable、Future 和 FutureTask 简单应用(二)

简介: 多线程 - Callable、Future 和 FutureTask 简单应用(二)

FutureTask类

FutureTask的实现

public class FutureTask<V> implements RunnableFuture<V> {}

FutureTask类实现了RunnableFuture接口,我们看一下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();
}

public interface RunnableFuture extends Runnable, Future {

   /**

    * Sets this Future to the result of its computation

    * unless it has been cancelled.

    */

   void run();

}


image.png


  • 当FutureTask处于未启动或已启动状态时,如果此时我们执行FutureTask.get()方法将导致调用线程阻塞;当FutureTask处于已完成状态时,执行FutureTask.get()方法将导致调用线程立即返回结果或者抛出异常。
  • 当FutureTask处于未启动状态时,执行FutureTask.cancel()方法将导致此任务永远不会执行。
    当FutureTask处于已启动状态时,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果任务取消成功,cancel(...)返回true;但如果执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时cancel(...)返回false。
    当任务已经完成,执行cancel(...)方法将返回false。
  • FutureTask 构造函数
public FutureTask(Callable<V> callable) {
}
public FutureTask(Runnable runnable, V result) {
}

简单使用案例

在互联网应用中有时候可能数据量会很大会把数据存储在不同的服务器,查询的时候会去查询不通的服务器,然后在把数据汇总,传统查询查完 A 服务器 再去 查询 B 服务然后在汇总,这样可能会导致等带的时间会比较长,使用 future 带返回值得线程就可以很好的解决这样的问题,在查询 A 服务器的同时去查询 B 服务器,最后在把数据汇总,例如


public class ExecutorFutureDemo implements Callable<Integer> {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        long startTime = System.currentTimeMillis();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                1,
                0L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());
        Future<Integer> result = executor.submit(new ExecutorFutureDemo());
        System.out.println("开始查询服务器 B ...");
        // 保存服务器 B 查询结果
        int sum = 0;
        // 主线程查询服务器 B 的结果
        for (int i = 1; i <= 100 ; i++) {
            sum += i;
        }
        // 模拟服务器 B 的查询时间
        Thread.sleep(3000);
        System.out.println("服务器 B 查询完毕。");
        if(!result.isDone()){
            System.out.println("服务器 A 数数据还没有查询完毕...");
        }
        // 在没有得到结果之前会一直阻塞在这里,直到拿到返回结果
        Integer aSum = result.get();
        long endTime = System.currentTimeMillis();
        System.out.println("查询结果="+(aSum+sum)+",总耗时="+(endTime-startTime)/1000);
        // 关闭线程池
        executor.shutdown();
    }
    @Override
    public Integer call() throws Exception {
        System.out.println("开始查询服务器 A ...");
        // 保存服务器 A 查询结果
        int sum = 0;
        try {
            // 模拟服务器 A 的 查询时间
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 1; i <= 50 ; i++) {
            sum += i;
        }
        System.out.println("服务器 A 查询完毕。");
        return sum;
    }
} 

结果

开始查询服务器 B ...
开始查询服务器 A ...
服务器 B 查询完毕。
服务器 A 数数据还没有查询完毕...
服务器 A 查询完毕。
查询结果=6325,总耗时= 5 秒

传统查询需要 8 秒,而示例只需要 5 秒即可。

目录
相关文章
|
2月前
|
Java Android开发 UED
🧠Android多线程与异步编程实战!告别卡顿,让应用响应如丝般顺滑!🧵
【7月更文挑战第28天】在Android开发中,确保UI流畅性至关重要。多线程与异步编程技术可将耗时操作移至后台,避免阻塞主线程。我们通常采用`Thread`类、`Handler`与`Looper`、`AsyncTask`及`ExecutorService`等进行多线程编程。
43 2
|
10天前
|
并行计算 Java 大数据
Callable和Future
Callable和Future
|
1月前
|
存储 SQL 缓存
揭秘Java并发核心:深度剖析Java内存模型(JMM)与Volatile关键字的魔法底层,让你的多线程应用无懈可击
【8月更文挑战第4天】Java内存模型(JMM)是Java并发的核心,定义了多线程环境中变量的访问规则,确保原子性、可见性和有序性。JMM区分了主内存与工作内存,以提高性能但可能引入可见性问题。Volatile关键字确保变量的可见性和有序性,其作用于读写操作中插入内存屏障,避免缓存一致性问题。例如,在DCL单例模式中使用Volatile确保实例化过程的可见性。Volatile依赖内存屏障和缓存一致性协议,但不保证原子性,需与其他同步机制配合使用以构建安全的并发程序。
55 0
|
2月前
|
Java 编译器
创建线程方式及应用总结
创建线程方式及应用总结
26 0
|
19天前
|
Java 数据库
异步&线程池 CompletableFuture 异步编排 实战应用 【终结篇】
这篇文章通过一个电商商品详情页的实战案例,展示了如何使用`CompletableFuture`进行异步编排,以解决在不同数据库表中查询商品信息的问题,并提供了详细的代码实现和遇到问题(如图片未显示)的解决方案。
异步&线程池 CompletableFuture 异步编排 实战应用 【终结篇】
|
3天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
26天前
|
调度 Android开发 开发者
【颠覆传统!】Kotlin协程魔法:解锁Android应用极速体验,带你领略多线程优化的无限魅力!
【8月更文挑战第12天】多线程对现代Android应用至关重要,能显著提升性能与体验。本文探讨Kotlin中的高效多线程实践。首先,理解主线程(UI线程)的角色,避免阻塞它。Kotlin协程作为轻量级线程,简化异步编程。示例展示了如何使用`kotlinx.coroutines`库创建协程,执行后台任务而不影响UI。此外,通过协程与Retrofit结合,实现了网络数据的异步加载,并安全地更新UI。协程不仅提高代码可读性,还能确保程序高效运行,不阻塞主线程,是构建高性能Android应用的关键。
34 4
|
8天前
|
Java 程序员 调度
Java中的多线程基础与实战应用
【8月更文挑战第30天】在Java的世界里,多线程是提升程序性能的利器,但也是新手开发者常碰壁的难点。本文旨在通过浅显易懂的语言和生动的比喻,带领读者走进Java多线程的大门。我们将从线程的基本概念出发,逐步深入到线程的创建、启动、管理以及同步机制,最后通过一个简易版的图书管理系统实例,展示如何在实际开发中灵活运用多线程技术。
|
24天前
三个线程交替打印ABC:技术深度解析与实战应用
【8月更文挑战第14天】在并发编程中,实现多个线程之间的精确协同工作是一项既具挑战性又极具实用价值的任务。今天,我们将深入探讨一个经典问题:如何使用三个线程交替打印字符A、B、C,且每个字符连续打印三次,之后循环进行。这个问题不仅考验了我们对线程同步机制的理解,还锻炼了我们在复杂并发场景下的设计能力。
39 0
|
27天前
|
Java
多线程 ThreadPoolTaskExecutor 应用
多线程 ThreadPoolTaskExecutor 应用
25 0