1.创建线程池
final ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
2.创建 http 请求
var builder = HttpRequest.newBuilder()
.uri(URI.create(uri));
HttpRequest request =
builder.POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8)).build();
//发送请求
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
3.创建任务,丢给线程池
List<CompletableFuture<?>> futures = new ArrayList<>();
for (User user : Users) {
CompletableFuture<?> future = CompletableFuture.runAsync(() -> {
用上面的 http 请求
}, threadPoolExecutor);
futures.add(future);
}
//等待所有任务完成
final int taskCount = futures.size();
CompletableFuture<?> allFuture = CompletableFuture.allOf((futures.toArray(new CompletableFuture[taskCount])));
allFuture.join();
//关闭线程池
threadPoolExecutor.shutdown();
4.User 数是 2000 多,也就是任务数才 2000 多,就把我系统资源爆了,提示不能再继续创建 thread 了,我的 macOS 直接黑屏重启
我寻思我创建的线程池才 5 个,不至于让我的系统挂了吧?那元凶可能是 http 新的 client api 自己再私自创建大量线程,直到耗尽系统的线程资源数?有无大佬指教一下怎么优化?我就想我请求只限制在 5 个线程以内
谢谢大家,我传入一个单线程的池子给httpclient的builder就没问题了。
1
buster 2021-09-10 11:19:10 +08:00
HttpRequest 看下有没有资源需要释放,close 之类的?
|
2
nutting 2021-09-10 11:31:28 +08:00
这么多 http 请求很多了
|
3
joyhub2140 OP @nutting 线程池才给 5 条线程做请求哦。
|
4
yazinnnn 2021-09-10 11:34:40 +08:00
val client: HttpClient = HttpClient.newBuilder().executor(threadPoolExecutor).build()
用这个试试? client.sendAsync() 发送请求用 HttpClient 的异步 api |
5
securityCoding 2021-09-10 11:36:51 +08:00
你给的信息太少,不知道你的代码具体结构怎么组织的,提供几个思路
1. client 可以复用(an HttpClient is immutable, and can be used to send multiple requests.) 2. 线程池复用,为什么要在方法内关闭呢? 3. allFuture.join()是否应该改成 allFuture.get() |
6
123zouwen 2021-09-10 11:38:56 +08:00 1
用之前至少先翻看一下 api 和源码吧
构建 HttpClient 的时候可以传入 Executor,查看源码没有传入会有一个默认的 Executors.newCachedThreadPool(new DefaultThreadFactory(id) 而且 jdk11 新的 HTTP client API 本身就可以发异步请求返回 CompletableFuture 一个 java11 httpclient 例子你简单看一下, https://github.com/app2smile/java11-HttpClient-Util/blob/main/JdkHttpClientUtil.java |
7
ForkNMB 2021-09-10 11:42:17 +08:00
首先,不建议使用 Executors.newFixedThreadPool 创建线程池,阻塞队列大小是没有大小限制的,如果队列堆积数据太多会造成资源消耗,手动指定一下线程池参数吧。
|
8
securityCoding 2021-09-10 11:43:02 +08:00
@123zouwen 看了一下源码,你是对的
|
9
wellsc 2021-09-10 12:02:09 +08:00
hhh
|
10
ikas 2021-09-10 13:20:19 +08:00
1.你这个 httpclient 根本就没有用你配置的 threadPoolExecutor ....
你只是自己写了一个异步 ,CompletableFuture.runAsync(() -> { 用上面的 http 请求 }, threadPoolExecutor); ,你应该直接用 httpclient 内置的 async 方法,同时给其配置线程池 2.你这么多请求全部等待...内存肯定耗尽了..所以 httpclient 内部也没有办法创建进程了.. 3.内存崩了系统挂了..那么应该是系统问题.... |
11
BBCCBB 2021-09-10 14:10:47 +08:00
所以看起来是 sendAsync 的时候用的默认的 CachedThreadPool() 导致的创建了太多线程?
这个线程看起来是异步执行完后的回调线程. 是 completeAsync(() -> null, executor) 导致的? |
12
DonaldY 2021-09-10 14:22:28 +08:00
httpClient 线程池 没设置
|
13
dqzcwxb 2021-09-10 14:42:00 +08:00
啥也不知道就让别人改线程池参数是最搞笑的,说一句正确的废话
|
14
dqzcwxb 2021-09-10 14:48:35 +08:00
|
15
guyeu 2021-09-11 10:45:50 +08:00
|