Apache HttpClient - 多线程

  • 简述

    多线程程序包含两个或多个可以同时运行的部分,每个部分可以同时处理不同的任务,从而优化利用可用资源。
    你可以通过编写一个多线程的HttpClient程序来执行来自多个线程的请求。
    如果你想从线程中连续执行多个客户端请求,你需要创建一个ClientConnectionPoolManager。它维护一个 HttpClientConnections 池并为来自线程的多个请求提供服务。
    连接管理器根据路由对连接进行池化。如果管理器有特定路由的连接,那么它会通过从池中租用现有连接而不是创建新连接来为这些路由中的新请求提供服务。
    按照步骤执行来自多个线程的请求 -
  • 第 1 步 - 创建客户端连接池管理器

    通过实例化 PoolingHttpClientConnectionManager 类来创建客户端连接池管理器。
    
    PoolingHttpClientConnectionManager connManager = new
       PoolingHttpClientConnectionManager(); 
    
  • 第 2 步 - 设置最大连接数

    使用 setMaxTotal() 方法设置池中的最大连接数。
    
    //设置池中的最大连接数
    connManager.setMaxTotal(100);
    
  • 第 3 步 - 创建 ClientBuilder 对象

    通过使用 setConnectionManager() 方法设置连接管理器来创建一个 ClientBuilder 对象,如下所示 -
    
    HttpClientBuilder clientbuilder =
    HttpClients.custom().setConnectionManager(connManager);
    
  • 第 4 步 - 创建 HttpGet 请求对象

    通过将所需的 URI 作为参数传递给其构造函数来实例化 HttpGet 类。
    
    HttpGet httpget1 = new HttpGet("URI1");
    HttpGet httpget2 = new HttpGet("URI2");
    . . . . . . . . . . . .
    
  • 第 5 步 - 实现run方法

    确保你已经创建了一个类,使它成为一个线程(通过扩展线程类或通过实现 Runnable 接口)并实现了 run 方法。
    
    public class ClientMultiThreaded extends Thread {
       public void run() {
          //Run method implementation . . . . . . . . . .
       }
    }
    
  • 第 6 步 - 创建线程对象

    通过实例化上面创建的Thread类(ClientMultiThreaded)来创建线程对象。
    将一个 HttpClient 对象、相应的 HttpGet 对象和一个表示 ID 的整数传递给 这些线程。
    
    ClientMultiThreaded thread1 = new ClientMultiThreaded(httpclient,httpget1, 1);
    ClientMultiThreaded thread2 = new ClientMultiThreaded(httpclient,httpget2, 2);
    . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... . .
    . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    
  • 第 7 步 - 开始并加入线程

    启动所有线程使用 start() 方法并使用 join method() 加入它们。
    
    线程1.start();
    线程2.start();
    . . . . . . . .
    线程1.join();
    线程2.join();
    . . . . . . . . . . . .
    
  • 第 8 步 - 运行方法实现

    在run方法中,执行请求,获取响应并打印结果。
  • 示例

    下面的例子演示了从多个线程同时执行 HTTP 请求。在这个例子中,我们尝试执行来自不同线程的各种请求,并尝试打印状态,以及每个客户端读取的字节数。
    
    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.apache.http.util.EntityUtils;
    public class ClientMultiThreaded extends Thread {
       CloseableHttpClient httpClient;
       HttpGet httpget;
       int id;
     
       public ClientMultiThreaded(CloseableHttpClient httpClient, HttpGet httpget,
       int id) {
          this.httpClient = httpClient;
          this.httpget = httpget;
          this.id = id;
       }
       @Override
       public void run() {
          try{
             //Executing the request
             CloseableHttpResponse httpresponse = httpClient.execute(httpget);
             //Displaying the status of the request.
             System.out.println("status of thread "+id+":"+httpresponse.getStatusLine());
             //Retrieving the HttpEntity and displaying the no.of bytes read
             HttpEntity entity = httpresponse.getEntity();
             if (entity != null) {
                System.out.println("Bytes read by thread thread "+id+":
                   "+EntityUtils.toByteArray(entity).length);
             }
          }catch(Exception e) {
             System.out.println(e.getMessage());
          }
       }
          
       public static void main(String[] args) throws Exception {
          //Creating the Client Connection Pool Manager by instantiating the PoolingHttpClientConnectionManager class.
          PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
          //Set the maximum number of connections in the pool
          connManager.setMaxTotal(100);
          //Create a ClientBuilder Object by setting the connection manager
          HttpClientBuilder clientbuilder = HttpClients.custom().setConnectionManager(connManager);
     
          //Build the CloseableHttpClient object using the build() method.
          CloseableHttpClient httpclient = clientbuilder.build();
          //Creating the HttpGet requests
          HttpGet httpget1 = new HttpGet("http://www.cainiaoya.com/");
          HttpGet httpget2 = new HttpGet("http://www.google.com/");
          HttpGet httpget3 = new HttpGet("https://www.qries.com/");
          HttpGet httpget4 = new HttpGet("https://in.yahoo.com/");
     
          //Creating the Thread objects
          ClientMultiThreaded thread1 = new ClientMultiThreaded(httpclient,httpget1, 1);
          ClientMultiThreaded thread2 = new ClientMultiThreaded(httpclient,httpget2, 2);
          ClientMultiThreaded thread3 = new ClientMultiThreaded(httpclient,httpget3, 3);
          ClientMultiThreaded thread4 = new ClientMultiThreaded(httpclient,httpget4, 4);
          //Starting all the threads
          thread1.start();
          thread2.start();
          thread3.start();
          thread4.start();
          //Joining all the threads
          thread1.join();
          thread2.join();
          thread3.join();
          thread4.join();
       }
    }
    
  • 输出

    在执行时,上面的程序生成以下输出 -
    
    status of thread 1: HTTP/1.1 200 OK
    Bytes read by thread thread 1: 36907
    status of thread 2: HTTP/1.1 200 OK
    Bytes read by thread thread 2: 13725
    status of thread 3: HTTP/1.1 200 OK
    Bytes read by thread thread 3: 17319
    status of thread 4: HTTP/1.1 200 OK
    Bytes read by thread thread 4: 127018