jdk 8-future 异步处理-轮询isDone判断完成-springBoot示例

29 篇文章 0 订阅
23 篇文章 0 订阅

Future接口用于获取异步计算的结果,可通过get()获取结果、cancel()取消、isDone()判断是否完成等操作。
V get(): 获取结果,若无结果会阻塞至异步计算完成
V get(long timeOut, TimeUnit unit):获取结果,超时返回null
boolean isDone():执行结束(完成/取消/异常)返回true
boolean isCancelled():任务完成前被取消返回true
boolean cancel(boolean mayInterruptRunning):取消任务,未开始或已完成返回false,参数表示是否中断执行中的线程
java的Timer类来进行定时调用,schedule(TimerTask task, long delay)调度一个task,经过delay(ms)后开始进行调度,仅仅调度一次

参考

在 Java Future 上使用带有 isDone 和 Cancel 的轮询而不是阻塞 get
Future的isDone()方法结果为true代表了什么?
java Timer(定时调用、实现固定时间执行)
Java之Future(cancel,iSDone)
Java多线程任务超时结束的5种实现方法

操作

pom

    <!--基于Springboot-->
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.1.RELEASE</version>
        <relativePath/>
    </parent>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <skipTests>true</skipTests>

        <spring-boot.version>2.3.1.RELEASE</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

java测试代码

package ***.cfg;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * ExecutorPoolConfig 类说明:
 *
 * @author z.y
 * @version v1.0
 * @date 2022/7/27
 */
@Order
@Configuration
public class ExecutorPoolConfig {
    private static final Logger log = LoggerFactory.getLogger(ExecutorPoolConfig.class);
    @Bean ("taskNotifyThread")
    public AsyncTaskExecutor taskNotifyThread(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(10);
        executor.setKeepAliveSeconds(60);
        executor.setQueueCapacity(1);
        executor.setThreadNamePrefix("TASK-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        executor.initialize();
        log.info("线程池-初始化");
        return executor;
    }
    public void testPool(int size){
        try {
            size = Math.max(4,size);
            log.info("开始测试 线程池,数量 {}",size);
            AsyncTaskExecutor executor = taskNotifyThread();
            Map<String, Future<Boolean>> map = new HashMap<>(size);
            for (int i = 0; i < size; i++) {
                int index = i;
                map.put("T-"+index,executor.submit(() -> testOne(index)));
            }
            log.info("任务 已提交 线程池,数量 {}",size);
            Set<String> keySet = map.keySet();
            List<String> doneList = new ArrayList<>(size);
            // 方式1 使用 get 阻塞判断否结束--------------
            Boolean b;
            for (String key : keySet) {
                b = map.get(key).get();
                if(null != b){
                    log.info("get 阻塞判断是否结束,{}",b);
                    doneList.add(key);
                }
            }
            // 方式1 使用 get 阻塞判断是结束--------------

            // 方式2 使用 isDone 轮询判断是结束---------------
            Future<Boolean> future;
            while (keySet.size() != doneList.size()){
                for (String key : keySet) {
                    // 已结束的子任务 直接跳过
                    if(doneList.contains(key)){ continue; }
                    future = map.get(key);
                    if(future.isDone()){
                        doneList.add(key);
                        log.info("子任务已结束,{},{}",key,future.get());
                    }else{
                        log.info("子任务未结束-===-{}",key);
                    }
                }
                log.info("问了一遍,结束的任务:{},先睡1s",doneList);
                TimeUnit.SECONDS.sleep(1);
            }
            // 方式2 使用 isDone 轮询判断是结束---------------
            log.info("都已经处理结束,结束的顺序:{}",doneList);
        }catch (Exception e){
            log.error("任务测试失败",e);
        }
    }
    private Boolean testOne(int index){
        try {
            int i = ThreadLocalRandom.current().nextInt(2,10);
            log.info("子任务-{}-开始,睡眠:{}",index,i);
            TimeUnit.SECONDS.sleep(i);
            log.info("子任务-{}=====结束,睡眠:{}",index,i);
            return i % 2 == 0;
        }catch (Exception e){
            log.error("子任务测试失败",e);
        }
        return false;
    }
    @PostConstruct
    public void init(){
        log.info("配置类初始化完成");
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                log.info("线程池开始处理");
                testPool(6);
            }
        }, 2000);
    }
}

在这里插入图片描述

日志

方式2-轮询处理

2022-07-28 08:54:55.722  INFO 17952 --- [           main] ***.cfg.ExecutorPoolConfig  : 线程池-初始化
2022-07-28 08:54:55.723  INFO 17952 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'taskNotifyThread'
2022-07-28 08:54:55.992  INFO 17952 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9980 (http) with context path '/runner-demo'
2022-07-28 08:54:56.002  INFO 17952 --- [           main] ***.RunnerSpringDemoApplication      : Started RunnerSpringDemoApplication in 2.32 seconds (JVM running for 4.784)
2022-07-28 08:54:56.004  INFO 17952 --- [           main] ***.RunnerSpringDemoApplication      : http://127.0.0.1:9980/runner-demo/
2022-07-28 08:54:57.714  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 线程池开始处理
2022-07-28 08:54:57.714  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 开始测试 线程池,数量 6
2022-07-28 08:54:57.715  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 任务 已提交 线程池,数量 6
2022-07-28 08:54:57.716  INFO 17952 --- [         TASK-4] ***.cfg.ExecutorPoolConfig  : 子任务-4-开始,睡眠:2
2022-07-28 08:54:57.716  INFO 17952 --- [         TASK-3] ***.cfg.ExecutorPoolConfig  : 子任务-3-开始,睡眠:3
2022-07-28 08:54:57.716  INFO 17952 --- [         TASK-5] ***.cfg.ExecutorPoolConfig  : 子任务-5-开始,睡眠:9
2022-07-28 08:54:57.716  INFO 17952 --- [         TASK-1] ***.cfg.ExecutorPoolConfig  : 子任务-0-开始,睡眠:2
2022-07-28 08:54:57.716  INFO 17952 --- [         TASK-2] ***.cfg.ExecutorPoolConfig  : 子任务-2-开始,睡眠:4
2022-07-28 08:54:57.716  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-2
2022-07-28 08:54:57.716  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-1
2022-07-28 08:54:57.716  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-4
2022-07-28 08:54:57.716  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-3
2022-07-28 08:54:57.717  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-5
2022-07-28 08:54:57.717  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-0
2022-07-28 08:54:57.717  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 问了一遍,结束的任务:[],先睡1s
2022-07-28 08:54:58.717  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-2
2022-07-28 08:54:58.717  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-1
2022-07-28 08:54:58.717  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-4
2022-07-28 08:54:58.717  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-3
2022-07-28 08:54:58.717  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-5
2022-07-28 08:54:58.717  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-0
2022-07-28 08:54:58.717  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 问了一遍,结束的任务:[],先睡1s
2022-07-28 08:54:59.717  INFO 17952 --- [         TASK-4] ***.cfg.ExecutorPoolConfig  : 子任务-4=====结束,睡眠:2
2022-07-28 08:54:59.717  INFO 17952 --- [         TASK-1] ***.cfg.ExecutorPoolConfig  : 子任务-0=====结束,睡眠:2
2022-07-28 08:54:59.717  INFO 17952 --- [         TASK-4] ***.cfg.ExecutorPoolConfig  : 子任务-1-开始,睡眠:4
2022-07-28 08:54:59.718  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-2
2022-07-28 08:54:59.718  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-1
2022-07-28 08:54:59.718  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务已结束,T-4,true
2022-07-28 08:54:59.718  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-3
2022-07-28 08:54:59.718  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-5
2022-07-28 08:54:59.718  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务已结束,T-0,true
2022-07-28 08:54:59.718  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 问了一遍,结束的任务:[T-4, T-0],先睡1s
2022-07-28 08:55:00.717  INFO 17952 --- [         TASK-3] ***.cfg.ExecutorPoolConfig  : 子任务-3=====结束,睡眠:3
2022-07-28 08:55:00.719  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-2
2022-07-28 08:55:00.719  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-1
2022-07-28 08:55:00.719  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务已结束,T-3,false
2022-07-28 08:55:00.719  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-5
2022-07-28 08:55:00.719  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 问了一遍,结束的任务:[T-4, T-0, T-3],先睡1s
2022-07-28 08:55:01.716  INFO 17952 --- [         TASK-2] ***.cfg.ExecutorPoolConfig  : 子任务-2=====结束,睡眠:4
2022-07-28 08:55:01.720  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务已结束,T-2,true
2022-07-28 08:55:01.720  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-1
2022-07-28 08:55:01.720  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-5
2022-07-28 08:55:01.720  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 问了一遍,结束的任务:[T-4, T-0, T-3, T-2],先睡1s
2022-07-28 08:55:02.721  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-1
2022-07-28 08:55:02.721  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-5
2022-07-28 08:55:02.721  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 问了一遍,结束的任务:[T-4, T-0, T-3, T-2],先睡1s
2022-07-28 08:55:03.718  INFO 17952 --- [         TASK-4] ***.cfg.ExecutorPoolConfig  : 子任务-1=====结束,睡眠:4
2022-07-28 08:55:03.721  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务已结束,T-1,true
2022-07-28 08:55:03.721  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-5
2022-07-28 08:55:03.721  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 问了一遍,结束的任务:[T-4, T-0, T-3, T-2, T-1],先睡1s
2022-07-28 08:55:04.722  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-5
2022-07-28 08:55:04.722  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 问了一遍,结束的任务:[T-4, T-0, T-3, T-2, T-1],先睡1s
2022-07-28 08:55:05.723  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务未结束-===-T-5
2022-07-28 08:55:05.723  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 问了一遍,结束的任务:[T-4, T-0, T-3, T-2, T-1],先睡1s
2022-07-28 08:55:06.716  INFO 17952 --- [         TASK-5] ***.cfg.ExecutorPoolConfig  : 子任务-5=====结束,睡眠:9
2022-07-28 08:55:06.723  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 子任务已结束,T-5,false
2022-07-28 08:55:06.723  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 问了一遍,结束的任务:[T-4, T-0, T-3, T-2, T-1, T-5],先睡1s
2022-07-28 08:55:07.724  INFO 17952 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 都已经处理结束,结束的顺序:[T-4, T-0, T-3, T-2, T-1, T-5]

方式1-阻塞获取

--2022-07-29 10:19:25.436 - INFO 19288 --- [           main] ***.cfg.ExecutorPoolConfig  : 线程池-初始化
--2022-07-29 10:19:25.438 - INFO 19288 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'taskNotifyThread'
--2022-07-29 10:19:25.819 - INFO 19288 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9980 (http) with context path '/runner-demo'
--2022-07-29 10:19:25.831 - INFO 19288 --- [           main] ***.RunnerSpringDemoApplication      : Started RunnerSpringDemoApplication in 3.103 seconds (JVM running for 6.078)
--2022-07-29 10:19:25.834 - INFO 19288 --- [           main] ***.RunnerSpringDemoApplication      : http://127.0.0.1:9980/runner-demo/
--2022-07-29 10:19:27.424 - INFO 19288 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 线程池开始处理
--2022-07-29 10:19:27.424 - INFO 19288 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 开始测试 线程池,数量 6
--2022-07-29 10:19:27.427 - INFO 19288 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 任务 已提交 线程池,数量 6
--2022-07-29 10:19:27.427 - INFO 19288 --- [         TASK-5] ***.cfg.ExecutorPoolConfig  : 子任务-5-开始,睡眠:6
--2022-07-29 10:19:27.427 - INFO 19288 --- [         TASK-2] ***.cfg.ExecutorPoolConfig  : 子任务-2-开始,睡眠:2
--2022-07-29 10:19:27.427 - INFO 19288 --- [         TASK-1] ***.cfg.ExecutorPoolConfig  : 子任务-0-开始,睡眠:7
--2022-07-29 10:19:27.427 - INFO 19288 --- [         TASK-4] ***.cfg.ExecutorPoolConfig  : 子任务-4-开始,睡眠:2
--2022-07-29 10:19:27.427 - INFO 19288 --- [         TASK-3] ***.cfg.ExecutorPoolConfig  : 子任务-3-开始,睡眠:7
--2022-07-29 10:19:29.429 - INFO 19288 --- [         TASK-2] ***.cfg.ExecutorPoolConfig  : 子任务-2=====结束,睡眠:2
--2022-07-29 10:19:29.429 - INFO 19288 --- [         TASK-4] ***.cfg.ExecutorPoolConfig  : 子任务-4=====结束,睡眠:2
--2022-07-29 10:19:29.429 - INFO 19288 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : get 阻塞判断是否结束,true
--2022-07-29 10:19:29.429 - INFO 19288 --- [         TASK-4] ***.cfg.ExecutorPoolConfig  : 子任务-1-开始,睡眠:3
--2022-07-29 10:19:32.430 - INFO 19288 --- [         TASK-4] ***.cfg.ExecutorPoolConfig  : 子任务-1=====结束,睡眠:3
--2022-07-29 10:19:32.430 - INFO 19288 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : get 阻塞判断是否结束,false
--2022-07-29 10:19:32.431 - INFO 19288 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : get 阻塞判断是否结束,true
--2022-07-29 10:19:33.429 - INFO 19288 --- [         TASK-5] ***.cfg.ExecutorPoolConfig  : 子任务-5=====结束,睡眠:6
--2022-07-29 10:19:34.429 - INFO 19288 --- [         TASK-1] ***.cfg.ExecutorPoolConfig  : 子任务-0=====结束,睡眠:7
--2022-07-29 10:19:34.429 - INFO 19288 --- [         TASK-3] ***.cfg.ExecutorPoolConfig  : 子任务-3=====结束,睡眠:7
--2022-07-29 10:19:34.429 - INFO 19288 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : get 阻塞判断是否结束,false
--2022-07-29 10:19:34.429 - INFO 19288 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : get 阻塞判断是否结束,true
--2022-07-29 10:19:34.429 - INFO 19288 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : get 阻塞判断是否结束,false
--2022-07-29 10:19:34.429 - INFO 19288 --- [        Timer-0] ***.cfg.ExecutorPoolConfig  : 都已经处理结束,结束的顺序:[T-2, T-1, T-4, T-3, T-5, T-0]
-

结束

get阻塞方式,任务不是最早结束的就能得到结果值,是按照自定义key的 顺序获取结果。
isDone轮询方式,任务是在主线程循环判断,结果顺序是和任务耗时有关,代码较多。
个人见解,如有问题请指出。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值