【Java并发】聊聊Future如何提升商品查询速度

这篇具有很好参考价值的文章主要介绍了【Java并发】聊聊Future如何提升商品查询速度。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

java中可以通过new thread、实现runnable来进行实现线程。但是唯一的缺点是没有返回值、以及抛出异常,而callable就可以解决这个问题。通过配合使用futuretask来进行使用。
并且Future提供了对任务的操作,取消,查询是否完成,获取结果。

Demo

        FutureTask<Integer> futureTask = new FutureTask<Integer>(() -> {
            Thread.sleep(10000);
            System.out.println("调用三方翻译接口");
            return 1024;
        });

        new Thread(futureTask).start();

        Integer integer = futureTask.get();
//        Integer integer = futureTask.get(1, TimeUnit.SECONDS);

        while (true) {
            if (futureTask.isDone()) {
                System.out.println("完成任务");
                break;
            } else {
                System.out.println("执行中,稍等.");
            }
        }
        Integer x = futureTask.get();
        System.out.println(x);

【Java并发】聊聊Future如何提升商品查询速度,# 并发编程,java,开发语言

实现原理

FutureTask核心代码

基本属性

     /* 
     *  Possible state transitions:
     * NEW -> COMPLETING -> NORMAL 任务正常执行,返回结果是正常的结果
     * NEW -> COMPLETING -> EXCEPTIONAL 任务正常执行,但是返回结果是异常
     * NEW -> CANCELLED  任务直接被取消的流程
     * NEW -> INTERRUPTING -> INTERRUPTED  
     */
     // 当前任务的状态
    private volatile int state;
    private static final int NEW          = 0; // 任务的初始化状态
    private static final int COMPLETING   = 1; // Callable的结果,正常封装给当前FutureTask
    private static final int NORMAL       = 2; // Normal任务正常结束
    private static final int EXCEPTIONAL  = 3; // 执行任务时,发生了异常
    private static final int CANCELLED    = 4; // 任务被取消了
    private static final int INTERRUPTING = 5; // 线程的中断状态,被设置为了ture 
    private static final int INTERRUPTED  = 6; // 线程被中断了

    // 当前要执行的任务
    private Callable<V> callable;
    // 存放任务返回结果的属性,也就是futureTask.get 需要获取的结果
    private Object outcome; 
    // 执行任务的线程
    private volatile Thread runner;
    // 单向链表,存放通过get方法挂起等待的线程
    private volatile WaitNode waiters;

任务

当线程start() 之后其实执行的就是call()方法。也就是通过futureTask的run方法执行的call()方法。

    // run方法的执行流程,最终会执行callable的call方法
    public void run() {
        // 保证任务的状态是NEW才执行,或者CAS将当前线程设置为runner.
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
        // 准备执行任务
            Callable<V> c = callable;
            // 任务不为null 并且state==new
            if (c != null && state == NEW) {
                V result; // 返回的结果
                boolean ran; // 任务执行是否正常结束
                try { 
                    // 调用callable的call方法。
                    result = c.call();
                    ran = true; // 正常结束 ran = true
                } catch (Throwable ex) {
                    result = null; // 异常结果为null 
                    ran = false; // 异常结束 ran = false
                    setException(ex); // 设置异常信息
                }
                if (ran) 
                    // 正常执行结束,设置返回结果
                    set(result);
            }
        } finally {
      		// 执行完毕 或者异常 ,都将runner设置为null 
            runner = null;
            // 拿到状态
            int s = state;
            // 如果中断 要做一些事情
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

    //设置result值
    protected void set(V v) {
        // cas设置state为 new-completing
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v; // 返回结果给outcome
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
			// 下面说
            finishCompletion();
        }
    }

get

get方法获取返回结果,到挂起的位置

    public V get() throws InterruptedException, ExecutionException {
        //拿状态
        int s = state;
        //满足未完成状态 就需要等待
        if (s <= COMPLETING)
        // 挂起线程,等待拿结果。
            s = awaitDone(false, 0L);
        return report(s);
    }
    //线程要等待任务执行结束,等待任务执行的状态大于completing状态
    private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        // dealline get() 就是0 ,如果是get(time,unit) 追加当前系统时间
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        // 构建waitNode 
        WaitNode q = null;
        boolean queued = false;
        //死循环
        for (;;) {
             //判断get线程是否中断了
            if (Thread.interrupted()) {
                //将当前节点从waiter中移除
                removeWaiter(q);
                //并且抛出中断异常
                throw new InterruptedException();
            }
			// 拿到现在任务的状态
            int s = state;
            // 判断任务是否执行完毕
            if (s > COMPLETING) {
                // q != null。表示设置过了 直接移除waitNode线程
                if (q != null)
                    q.thread = null;
                    //返回当前任务状态
                return s;
            }
            // 如果任务的状态处于completing 
            else if (s == COMPLETING) // cannot time out yet
               //让步
                Thread.yield();
            else if (q == null)
                // 线程状态还是new  call方法可能还没有执行 准备挂起线程
                // 封装waitNode存放当前线程
                q = new WaitNode();
            else if (!queued)
                // 如果waitNode还没有排在waiters中,就拍进来(头插法) cas修改
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                     q.next = waiters, q);
                // 如果get(time,unit)挂起线程方式
            else if (timed) {
                // 计算挂起时间
                nanos = deadline - System.nanoTime();
                // 挂起时间 是否小于等于0 
                if (nanos <= 0L) {
                    // 移除waiter 当前node
                    removeWaiter(q);
                    // 返回任务状态
                    return state;
                }
                //正常指定挂起时间即可
                LockSupport.parkNanos(this, nanos);
            }
            else
                //get()挂起线程的方式
                LockSupport.park(this);
        }
    }

   

finishCompletion唤醒线程

线程挂起后,如果任务执行完毕,由finishCompletioon唤醒线程

    private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            // 拿到第一个阶段,cas的方式修改 将其设置为null 
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                for (;;) {
                   // 拿到q线程信息
                    Thread t = q.thread;
                    // 线程信息不为空
                    if (t != null) {
                       // 将waitNode的thread设置为null 
                        q.thread = null;
                        // 唤醒这个线程
                        LockSupport.unpark(t);
                    }
                    //往后遍历 接着唤醒
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    //执行next的waitNode 
                    q = next;
                }
                break;
            }
        }
 
 		//拓展方法 没任何实现 
        done();

		//任务执行完毕
        callable = null;        // to reduce footprint
    }

report

// 任务结束。
private V report(int s) throws ExecutionException {
    // 拿到结果
    Object x = outcome;
    // 判断是正常返回结束
    if (s == NORMAL)
        // 返回结果
        return (V)x;
    // 任务状态是大于取消
    if (s >= CANCELLED)
        // 甩异常。
        throw new CancellationException();
    // 扔异常。
    throw new ExecutionException((Throwable)x);
}

// 正常返回 report
// 异常返回 report
// 取消任务 report
// 中断任务 awaitDone

流程图

【Java并发】聊聊Future如何提升商品查询速度,# 并发编程,java,开发语言文章来源地址https://www.toymoban.com/news/detail-822908.html

到了这里,关于【Java并发】聊聊Future如何提升商品查询速度的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java并发编程:Callable、Future和FutureTask

    在前面的文章中我们讲述了创建线程的 2 种方式,一种是直接继承 Thread ,另外一种就是实现 Runnable 接口。 这 2 种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。 如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起

    2024年02月13日
    浏览(38)
  • MySQL索引优化:提升查询速度的实战解析

    当涉及到大型数据库和复杂查询时,索引在MySQL中是一个重要的性能优化工具。通过使用索引,可以加速查询速度,减少查询的执行时间。下面是一个详细的MySQL添加索引的教程,使用Markdown格式进行说明。 步骤1:选择合适的列 首先,需要选择哪些列需要添加索引。通常情况

    2024年02月12日
    浏览(67)
  • 并发编程 | 从Future到CompletableFuture - 简化 Java 中的异步编程

    在并发编程中,我们经常需要处理多线程的任务,这些任务往往具有依赖性,异步性,且需要在所有任务完成后获取结果。Java 8 引入了 CompletableFuture 类,它带来了一种新的编程模式,让我们能够以函数式编程的方式处理并发任务,显著提升了代码的可读性和简洁性。 在这篇

    2024年02月13日
    浏览(49)
  • mysql语句中order by的查询速度太慢 请问需要做出哪些优化策略来提升查询速度...

    如果在MySQL中使用 order by 语句导致查询速度过慢,可以考虑以下优化策略: 使用索引:为排序字段建立索引可以提高查询速度。 增加内存:如果服务器内存不足,MySQL可能需要使用临时表或磁盘排序,增加内存可以避免这种情况。 减少数据量:使用 limit 语句可以限制结果集

    2024年02月13日
    浏览(50)
  • 查询速度提升15倍!银联商务基于 Apache Doris 的数据平台升级实践

    本文导读: 在长期服务广大规模商户的过程中,银联商务已沉淀了庞大、真实、优质的数据资产数据,这些数据不仅是银联商务开启新增长曲线的基础,更是进一步服务好商户的关键支撑。为更好提供数据服务,银联商务实现了从 Hadoop 到 Apache Doris 的架构升级,使数据 导入

    2024年02月02日
    浏览(55)
  • 如何优化vue项目 如何提升速度

    优化 Vue 项目和提升速度可以从多个方面入手。下面是一些常见的优化技巧: 使用生产环境构建:在部署项目时,使用 Vue 的生产环境构建可以去除开发环境的调试工具和警告信息,减小项目的体积。 代码拆分和懒加载:将项目代码拆分成多个小模块,并使用 Vue 的异步组件

    2024年02月10日
    浏览(37)
  • xbox如何提升下载速度?

    提高Xbox的下载速度可以通过以下几种方法: 连接稳定的网络 :使用有线以太网连接而不是无线连接,因为有线连接通常更稳定且速度更快。 关闭正在运行的游戏和应用程序 :运行游戏或应用程序会消耗网络资源和处理能力,关闭它们可以加快下载速度。 限制网络上的其他

    2024年01月16日
    浏览(31)
  • Xbox如何提升下载速度

    Xbox下载速度慢可能是由于多种原因,包括网络连接问题、微软服务器问题等。以下是一些可以尝试的方法,以提高Xbox的下载速度: 检查网络连接 :首先确保您的网络连接稳定且速度足够快。您可以尝试在其他设备上测试网络速度,以确保问题不在于您的网络。 重启Xbox和路

    2024年01月22日
    浏览(62)
  • 如何提升宽带路由器上网速度

    故障问题: 有两台电脑要共享上网,因此安装了宽带路由器,可是就算只有一台电脑在上网,速度也很慢。 故障处理: 通过宽带路由器共享上网,会使上网速度存在一定的损耗,这是避免不了的。通过更改路由器的MTU值可以将这个损耗降至最低。MTU值的意思是网络上传送的

    2024年02月06日
    浏览(86)
  • java多线程处理list,速度提升嗖嗖的!

    目录 项目场景 问题描述 解决方案: 方法一:没有返回值,直接在任务里完成计算 方法二:有返回值 最后 前台通过模板批量上传数据到后台 后台使用常规方法处理数据,效率低下 使用多线程线程池实现 除了创建线程池和分割 List 的过程外,主要的变化是将 Task 类改为实现

    2024年02月08日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包