依赖 OkHttp 12345<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.9.3</version></dependency> apache httpclient 123456789101112<!--同步请求模块--><dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.14</version></dependency><!--异步请求模块--><dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpasyncclient</artifactId> <version>4.1.5</version></dependency> 代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163public class HttpClient { static List<String> urlList = new ArrayList<>(); static { Logger logger = (Logger) LoggerFactory.getLogger("org.apache.http"); // 设置日志级别为OFF logger.setLevel(Level.OFF); for (int i = 0; i < 100; i++) { urlList.add("http://127.0.0.1:8080/query"); } } public static void main(String[] args) throws IOException, InterruptedException {// okHttpSync();// okHttpAsync();// apacheHttpSync();// apacheHttpAsync(); } public static OkHttpClient okHttpClient() { Dispatcher dispatcher = new Dispatcher(); //maxRequests和maxRequestsPerHost是同时能够请求的数量,底层通过两个队列存储,但是只会计算异步请求的数量,不过异步请求占满了之后同步请求也会被拒绝 dispatcher.setMaxRequests(20); dispatcher.setMaxRequestsPerHost(10);//maxRequestsPerHost记录同ip的请求 //okhttp连接池底层是链表,所以大小没有限制,底层也没有提供最大连接数,只提供了,最大空闲连接以及最大空闲时间 ConnectionPool connectionPool = new ConnectionPool(10, 10, TimeUnit.SECONDS); return new OkHttpClient().newBuilder().connectionPool(connectionPool).dispatcher(dispatcher).build(); } public static void okHttpSync() { OkHttpClient client = okHttpClient(); /** * 同步请求 底层使用Socket */ AtomicInteger i = new AtomicInteger(); ExecutorService executorService = Executors.newCachedThreadPool(); CountDownLatch countDownLatch = new CountDownLatch(100); for (String url : urlList) { executorService.execute(() -> { Request request = new Request.Builder() .url(url) .build(); try { Response response = client.newCall(request).execute(); System.out.println(response.body().string() + "----" + i.getAndIncrement()); countDownLatch.countDown(); } catch (Exception e) { throw new RuntimeException(e); } }); } executorService.shutdown(); try { countDownLatch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } } public static void okHttpAsync() { OkHttpClient client = okHttpClient(); /** * 异步请求 底层使用Socket,原理是将请求作为任务保存到队列,交给专门处理异步请求的线程处理请求,请求完成后调用回调函数, * 异步请求底层使用的是缓存线程池,即同时有多少异步请求,就同时创建多少线程 */ urlList.forEach(url -> { Request request = new Request.Builder() .url(url) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { System.out.println("请求失败"); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { System.out.println(response.body().string()); } }); }); } public static void apacheHttpSync() { /** * maxConnTotal是最大连接数,和okhttp不同,apache httpclient连接数是可以设置的,底层使用的也是链表,defaultSocketConfig是路由最大连接数, * 这里的路由是具体到端口的,而okhttp只会到ip */ CloseableHttpClient httpclient = HttpClients.custom().setMaxConnTotal(20).setMaxConnPerRoute(20).build(); AtomicInteger i = new AtomicInteger(); ExecutorService executorService = Executors.newCachedThreadPool(); CountDownLatch countDownLatch = new CountDownLatch(urlList.size()); urlList.forEach(url -> { executorService.execute(() -> { try { CloseableHttpResponse response = httpclient.execute(new HttpGet(url)); System.out.println(IoUtil.readUtf8(response.getEntity().getContent()) + "----" + i.getAndIncrement()); response.close(); countDownLatch.countDown(); } catch (IOException e) { throw new RuntimeException(e); } }); }); executorService.shutdown(); try { countDownLatch.await(); httpclient.close(); } catch (InterruptedException | IOException e) { throw new RuntimeException(e); } } public static void apacheHttpAsync() { /** * 底层使用NIO,所以不受线程的限制,数据会先写入到conn.getContext().getAttribute(HTTP_HANDLER)中(org.apache.http.impl.nio.client.AbstractClientExchangeHandler),conn为httpclient异步请求自定义的连接,底层有一个IOReactor的类, * 会调用系统方法获取那些channel是可以写入的,然后访问连接的SessionOutputBufferImpl,如果有数据,则直接写入channel,发送给服务端,如果没有数据,则将conn.getContext().getAttribute(HTTP_HANDLER) * 中的数据写入然后访问SessionOutputBufferImpl中,然后进行发送,虽然异步请求不受线程多少影响,但是这里用到了多线程,IOReactor有一个AbstractMultiworkerIOReactor实现类, * 它会创建多个(电脑cpu核数)线程,每个线程都有一个独立的IOReactor并行处理数据 */ CloseableHttpAsyncClient asyncClient = HttpAsyncClients.custom().setMaxConnTotal(20).setMaxConnPerRoute(20).build(); asyncClient.start(); AtomicInteger i = new AtomicInteger(); for (String url : urlList) { asyncClient.execute(new HttpGet(url), new FutureCallback<HttpResponse>() { @Override public void completed(HttpResponse httpResponse) { try { System.out.println(IoUtil.readUtf8(httpResponse.getEntity().getContent()) + "----" + i.getAndIncrement()); } catch (IOException e) { throw new RuntimeException(e); } } @Override public void failed(Exception e) { } @Override public void cancelled() { } }); } }}