计时器是邪恶的!使用计时器或执行器或任何其他为每个请求创建线程/可运行对象的机制是一个非常糟糕的主意。请明智地思考,不要这样做。否则,您将很快遇到或多或少真实环境的各种内存问题。想象一下 1000 req/min 意味着 1000 个线程或工作线程/分钟。可怜的GC。我提出的解决方案只需要 1 个看门狗线程,可以节省您的资源时间和精力。基本上你做3个步骤。
- 将请求放入缓存。
- 完成后从缓存中删除请求。
- 中止在您的限制范围内未完成的请求。
你的缓存和看门狗线程可能看起来像这样。
import org.apache.http.client.methods.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;
public class RequestCache {
private static final long expireInMillis = 300000;
private static final Map<HttpUriRequest, Long> cache = new ConcurrentHashMap<>();
private static final ScheduledExecutorService exe = Executors.newScheduledThreadPool(1);
static {
// run clean up every N minutes
exe.schedule(RequestCache::cleanup, 1, TimeUnit.MINUTES);
}
public static void put(HttpUriRequest request) {
cache.put(request, System.currentTimeMillis()+expireInMillis);
}
public static void remove(HttpUriRequest request) {
cache.remove(request);
}
private static void cleanup() {
long now = System.currentTimeMillis();
// find expired requests
List<HttpUriRequest> expired = cache.entrySet().stream()
.filter(e -> e.getValue() > now)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
// abort requests
expired.forEach(r -> {
if (!r.isAborted()) {
r.abort();
}
cache.remove(r);
});
}
}
以及以下 sudo 代码如何使用缓存
import org.apache.http.client.methods.*;
public class RequestSample {
public void processRequest() {
HttpUriRequest req = null;
try {
req = createRequest();
RequestCache.put(req);
execute(req);
} finally {
RequestCache.remove(req);
}
}
}