JDK.Future.get() :多线程里获取线程执行结果,异步阻塞问题

为了保证系统响应迅速,需要寻找一种方法能够使调取接口能够异步执行,而Java正好提供了类似的方法,在java.util.concurrent中包含了Future相关的类,运用其中的一些类可以进行异步计算,以减少主线程的等待时间。比如启动一个main方法,main中又包含了若干个其它任务,在不使用Java future的情况下,main方法中的任务会同步阻塞执行,一个执行完成后,才能去执行另一个;如果使用java future,则main方法中的任务会异步执行,main方法不用等待一个任务的执行完成,只需往下执行就行。一个任务的执行结果又该怎么获取呢?这里就需要用到Future接口中的isDone()方法来判断任务是否执行完,如果执行完成则可获取结果,如果没有完成则需要等待。 可见虽然主线程中的多个任务是异步执行,但是无法确定任务什么时候执行完成,只能通过不断去监听以获取结果,所以这里是阻塞的。这样,可能某一个任务执行时间很长会拖累整个主任务的执行。

还是那句话,废话不多说,直接上代码:

package com.aplus.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @author whb
 */
@Slf4j
@RestController
@RequestMapping(value = "/api/guava")
public class GuavaController {

    public static final ExecutorService service = Executors.newCachedThreadPool();

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();

        // 任务1
        Future<Boolean> booleanTask = service.submit(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Thread.sleep(10000);
                return true;
            }
        });

        // 任务2
        Future<String> stringTask = service.submit(new Callable<String>() {

            @Override
            public String call() throws Exception {
                Thread.sleep(3000);
                return "Hello World";
            }
        });

        // 任务3
        Future<Integer> integerTask = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(2000);
                return new Random().nextInt(100);
            }
        });

        while (true) {
            if (booleanTask.isDone() && !booleanTask.isCancelled()) {
                Boolean result = booleanTask.get();
                System.err.println("任务1-10s: " + result);
                break;
            }
        }

        while (true) {
            if (stringTask.isDone() && !stringTask.isCancelled()) {
                String result = stringTask.get();
                System.err.println("任务2-3s: " + result);
                break;
            }
        }

        while (true) {
            if (integerTask.isDone() && !integerTask.isCancelled()) {
                Integer result = integerTask.get();
                System.err.println("任务3-2s:" + result);
                break;
            }
        }

        // 执行时间
        System.err.println("time: " + (System.currentTimeMillis() - start));

    }

}

解释一波:

启动一个线程池,有三个线程和三个任务,分别是线程1,线程2,线程3;线程1执行任务1(耗时10s),线程2执行任务2(耗时3s),线程3执行任务3(耗时2s);

Thread1  ——> Task1  10s
Thread2  ——> Task2  2s
Thread3  ——> Task3  3s

我们运行程序看效果:

因为我们一开始用 Thread1.get() 获取第一个线程的结果时,是阻塞的,而且我们假定任务1执行了10s钟,导致了线程2(3s就执行完任务)和线程3(2s就执行完任务)都执行完了任务,也不打印出来。那在实际业务中,这种方法肯定是不可取的。

所以接下来我们引入 Guava Future

发布了165 篇原创文章 · 获赞 103 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/qq_33101675/article/details/89247450