java异步线程池同时请求多个接口数据

Posted 日魂月魄

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java异步线程池同时请求多个接口数据相关的知识,希望对你有一定的参考价值。

 一、主要使用类

     1. ExecutorService

      java线程池类

     申明方式:ExecutorService exc = Executors.newFixedThreadPool(requestParameterArray.length()); 

     参数:requestParameterArray.length()是请求线程的总数量,其中每一个成员存放单个线程所需参数。

    代码:

    2.Future

      Future是一个接口,他提供给了我们方法来检测当前的任务是否已经结束,还可以等待任务结束并且拿到一个结果,通过调用Future的get()方法可以当任务结束后返回一个结果值,如果线程里的任何一个线程工作没有结束,则线程会自动阻塞,直到任务执行完毕,我们可以通过调用cancel()方法来停止一个任务,如果任务已经停止,则cancel()方法会返回true;如果任务已经完成或者已经停止了或者这个任务无法停止,则cancel()会返回一个false。当一个任务被成功停止后,他无法再次执行。isDone()和isCancel()方法可以判断当前工作是否完成和是否取消,他的作用通过callable的回调获得我们请求的结果。

    ExecutorService/Future的执行代码类

   

public class AAAThreadHttpRequest
{ 
    
      //首页返回所需的参数和接口,电影接口
    //热门电影
    private String hotfilmUrl = "http://expand.video.iqiyi.com/api/top/list.json?apiKey=?&topType=1&categoryId=1&limit=30&sr=1";
 //热门电视剧
    private String hotdianshijuUrl = "http://expand.video.iqiyi.com/api/top/list.json?apiKey=?&topType=1&categoryId=2&limit=5&sr=2";
 //热门动漫
    private String hotanimationUrl = "http://expand.video.iqiyi.com/api/top/list.json?apiKey=?&topType=1&categoryId=4&limit=5&sr=3";
 //第一个分段数据
     private String segmentOneUrl ="http://expand.video.iqiyi.com/api/top/list.json?apiKey=?&topType=1&categoryId=7&limit=6&sr=5";
     
     //淘宝客 
     
 
public      LinkedList<JSONObject>  ShiPinThreadHandle() throws JSONException, IOException, InterruptedException, ExecutionException
{
     //组合线程请求参数
    JSONArray requestParameterArray=new JSONArray();
     JSONObject  a=new JSONObject();
    a.put("requestUrl", hotfilmUrl);
    a.put("dataType", "hotFilm");
    a.put("type", "shipin");
    
    JSONObject  a1=new JSONObject();
    a1.put("requestUrl", hotdianshijuUrl);
    a1.put("dataType", "hotDianshiju");
    a1.put("type", "shipin");
    
    JSONObject  a2=new JSONObject();
    a2.put("requestUrl", hotanimationUrl);
    a2.put("dataType", "hotDongman");
    a2.put("type", "shipin");
    
 
    JSONObject  a3=new JSONObject();
    a3.put("requestUrl", segmentOneUrl);
    a3.put("dataType", "firstSegmentData");
    a3.put("type", "shipin");
    
    
    
   
    requestParameterArray.put(a);
    requestParameterArray.put(a1);
    requestParameterArray.put(a2);
    requestParameterArray.put(a3);
    
      //申明线程池
   ExecutorService exc = Executors.newFixedThreadPool(requestParameterArray.length());  
   //申明数据回调处理类List<Future<JSONObject>>
   List<Future<JSONObject>> futures = new ArrayList<Future< JSONObject>>();  
    for (int i =0; i < requestParameterArray.length(); i++) {  
     
       JSONObject singleobje=requestParameterArray.getJSONObject(i);
        //申请单个线程执行类
       ShiPinThreadHandleRequest call =new ShiPinThreadHandleRequest(singleobje);  
       //提交单个线程
      Future< JSONObject> future = exc.submit(call);  
      //将每个线程放入线程集合, 这里如果任何一个线程的执行结果没有回调,线程都会自动堵塞
      futures.add(future);  

   }  
   //所有线程执行完毕之后会执行下面的循环,然后通过循环每个个线程后执行线程的get()方法每个线程执行的结果
   for (Future< JSONObject> future : futures) {     
  
    JSONObject json= future.get();
    
     AAAANewAppShareSingleton.getInstance().homePageSessionDictionary.put(json.getString("dataType"), json.getJSONArray("returnData"));
 
   }  
   AAAANewAppShareSingleton.getInstance().homeIsOrNoReturn=1;
   
   //关闭线程池
   exc.shutdown();  
  
  
   
   //这里由于我直接将返回结果放入到单利中缓存了,所有返回null
    return null;
     
}

 

   3.Callable

    线程执行者,我们的数据将在这个类的构造函数里面执行,这个类自带了回调函数。当执行结果返回时会通过它自带的回调将请求结果反馈给Future。

   Callable执行代码类

   

public   class ShiPinThreadHandleRequest implements Callable<JSONObject> {  

      private  JSONObject parameter;
        
        public ShiPinThreadHandleRequest(JSONObject parameter) throws JSONException, IOException {  
             this.parameter=parameter;
        
              try
             {
       
             String htmlJson=httpGetRequest(this.parameter.getString("requestUrl"));
             JSONObject object=new JSONObject(HtmlJson);
             //请求的爱奇艺接口
            if(this.parameter.get("type").equals("shipin"))
            {
                JSONArray returnArray=object.getJSONArray("data");
            
                 
                
                
                  
                if(this.parameter.getString("dataType").equals("firstSegmentData"))
                {
                    
                     JSONArray againArray=new JSONArray();
                for (int j=0;j<returnArray.length();j++)
                {
                     JSONArray tempArrray=new JSONArray();
                    tempArrray.put(returnArray.getJSONObject(j));
                    tempArrray.put(returnArray.getJSONObject(j+1));

                    againArray.put(tempArrray);
                    j=j+1;

                }
                this.parameter.put("returnData",againArray);
                }
                else
                {
                      this.parameter.put("returnData",returnArray);
                }
                 
               
            }
          //请求的淘宝客接口
            else
            {
                
            }
            
              }
            catch(Exception e)
             {
                 
             }
             
          
      
    }  
  
    //数据回调
    public JSONObject call() throws Exception {  
       
       
        return this.parameter;  
    }
}

  4.http请求方法

    

public    String httpGetRequest(String urlString1) {
     
    String result = "";
    BufferedReader in = null;
    
    try {
      
        URL realUrl = new URL(urlString1);
        // 打开和URL之间的连接
        URLConnection connection = realUrl.openConnection();
        // 设置通用的请求属性
        connection.setRequestProperty("accept", "*/*");
        connection.setRequestProperty("connection", "Keep-Alive");
        connection.setRequestProperty("user-agent",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        // 建立实际的连接
        connection.connect();
        // 获取所有响应头字段
        Map<String, List<String>> map = connection.getHeaderFields();
        // 遍历所有的响应头字段
        for (String key : map.keySet()) {
           
        }
        // 定义 BufferedReader输入流来读取URL的响应
        in = new BufferedReader(new InputStreamReader(
                connection.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            result += line;
        }
    } catch (Exception e) {
        System.out.println("发送GET请求出现异常!" + e);
        e.printStackTrace();
    }
    // 使用finally块来关闭输入流
    finally {
        try {
            if (in != null) {
                in.close();
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }
    return result;

}

  二、适合的使用场景

      复杂的网页爬虫,如要同时请求多个不同网页的数据,并且需要执行不同的数据处理,这个是非常合适的,执行线程传递的参数到最后callback是会附带一起反馈,你可以根据请求时的附带的类型参数进行判断。 复杂的首页数据,同时需要请求不同数据库的不同接口。

三、优势

      解决了多线程中复杂的线程堵塞问题,因为有future,它已经给你做了所有的事。

 

以上是关于java异步线程池同时请求多个接口数据的主要内容,如果未能解决你的问题,请参考以下文章

GIL锁,线程池,同步异步

第十次总结 线程的异步和同步

GIL 线程池 进程池 同步 异步

HTTP异步连接池和多线程实践

Java 线程池

你可能写了个假异步,并不能提高请求线程池的吞吐量