jdk1.8的Future特性简介及使用场景

Future简介

什么是Future?

Future是一个接口,用来返回异步的结果。它表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,此方法在计算完成前可以被阻塞。

Future的使用场景

Future通常被使用在需要多个线程协作计算的情形中。

Future接口内部的常用方法

   1> cancel,取消Callable的执行,当Callable还没有完成时
   2> get,获得Callable的返回值
   3> isCanceled,判断是否取消了
   4> isDone,判断是否完成

Future的常见用法

一、基础用法:

重写Callable接口的call方法,放到异步线程的.submit方法中执行。

       可以直接重写call方法;
       也可以定义一个类继承Callable接口,在类中重写call方法.

代码实例:
package future.com;

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

class TaskWithResult implements Callable<String>{

	public String call() throws Exception {
		// TODO Auto-generated method stub
		Thread.sleep(1000);
		return "OK";
	}
}

public class CallableDemo {
	
	public static void main(String[] args) throws Exception {

		/**
		 * 一、直接重写call方法,然后在.submit方法中传入call
		 * */
		// 开启线程池
		final ExecutorService exec = Executors.newFixedThreadPool(3);
		// 直接重写Callable的call方法
		Callable<String> call = new Callable<String>() {
			public String call() throws Exception {
				return "Other less important but longtime things.";
			}
		};
		Future<String> task = exec.submit(call);
		
		/**
		 * Future线程类的常用方法
		 * */
		// 获取Callable返回值
		System.out.println(task.get());
		// 判断是否执行完成
		System.out.println(task.isDone());
		//当Callable没执行完成时,取消Callable的执行
		System.out.println(task.cancel(false));
		// 判断是否被取消
		System.out.println(task.isCancelled());

		/**
		 * 二、TaskWithResult类继承Callable接口,在类里面重写call方法,.submit方法中传入TaskWithResult类
		 * */
		Future<String> st=exec.submit(new TaskWithResult());
		System.out.println(st.get());
		
		// 关闭线程
		exec.shutdown();
	}
}

二、进阶用法:

定义返回值类型为进程类的方法,异步调用,阻塞等待。再对结果集进行处理

假定一个场景:
要循环调访问某些接口,并处理得到的数据。

具体实现:
1)service层定义一个返回值为进程类的请求方法,在该方法中请求数据并返回结果

package com.service;

package com.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.endtity.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.concurrent.Future;

@Service
public class JsonService {

    @Autowired
    private RestTemplate restTemplate;
    private ObjectMapper objectMapper = new ObjectMapper();

    @Async
    public Future<JsonResult> query(String url, Object param){
        JsonResult result = null;
        try {
            String json = restTemplate.postForObject(url, param, String.class);
            result = objectMapper.readValue(json, new TypeReference<JsonResult>(){});
        } catch (IOException e) {

        } finally {

        }
        return new AsyncResult<>(result);
    }
}

2)定义返回结果

com.endtity.JsonResult

package com.endtity;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
public class JsonResult {
    @JsonProperty("code")
    private String code;
    @JsonProperty("msg")
    private String msg;
    @JsonProperty("result")
    private Object result;
}

3)Controll层的实现

1> 异步调用取数据service的方法;
2> 阻塞等待,用isDone方法判断是否执行完成;
3> 合并结果集;
4> 按照自己的需求处理结果集,并返回处理后的结果

package com.api;

package com.api;

import com.endtity.JsonResult;
import com.service.JsonService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@RestController
@RequestMapping("/rest/api/track")
@CrossOrigin("*")
public class JsonControl {

    private Logger logger = LoggerFactory.getLogger(JsonControl.class);

    @Autowired
    private JsonService jsonservice;

    public static void main(String[] args) {
        SpringApplication.run(JsonControl.class, args);
    }

    @PostMapping("test")
    public List<JsonResult> test(@RequestBody Object json) throws InterruptedException, ExecutionException {

        // 配置要循环访问的接口地址
        List<String> ls = new ArrayList();
        ls.add("https://");
        ls.add("https://");

        List<JsonResult> result = null;
        Map<String, Future<JsonResult>> obj = new HashMap<>();

        // 异步调用
        for(int i=0; i<ls.size(); i++){
            Future<JsonResult> ss=jsonservice.query(ls.get(i), json);
            obj.put(i+"", ss);
        }
        
        // 阻塞等待
        while(true){
            boolean bool=true;
            for(int i=0;i<3;i++){
                if(bool&&obj.get(i+"").isDone()){
                    bool=true;
                }else{
                    bool=false;
                }
            }
            if(bool){
                break;
            }
        }
        
        // 合并结果集
        for(int i=0; i<ls.size(); i++){
            JsonResult o = obj.get(i+"").get();
            result.add(o);
        }

        // 对结果集进行聚合


		// 返回结果集
        return result;
    }
}

一些实现细节:

1)在写service层的进程类方法是,虽然进程执行完后丢给我们的是一个 JsonResult 的结果对象。但是在进程类中不能直接 return 一个 JsonResult 对象,而是应该 new 一个 异步进程结果AsyncResult<>()将方法的执行结果传出。
2)control层有一个 while 死循环,必须通过isDone()方法判断进程全部执行完后才能对结果集进行处理。
3)记得处理一些相关的异常

原创文章 19 获赞 16 访问量 2443

猜你喜欢

转载自blog.csdn.net/qq_42778289/article/details/103959293