我正在尝试来自Jersey文档(https://jersey.github.io/documentation/latest/async.html#d0e10146)的异步客户端和服务器端回调示例。
我正在使用Grizzle客户端连接器和服务器工厂。与示例的不同之处在于我通过for循环发送了10000个请求。我设置了一个clientConfig.property(ClientProperties.ASYNC_THREADPOOL_SIZE,20);
然后客户端抛出异常:
javax.ws.rs.ProcessingException: java.util.ConcurrentModificationException
at org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:227)
at org.glassfish.jersey.client.ClientRuntime.lambda$null$3(ClientRuntime.java:185)
at org.glassfish.jersey.client.ClientRuntime$$Lambda$103/1511834685.run(Unknown Source)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:312)
at org.glassfish.jersey.client.ClientRuntime.lambda$createRunnableForAsyncProcessing$4(ClientRuntime.java:159)
at org.glassfish.jersey.client.ClientRuntime$$Lambda$100/1987360300.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966)
at java.util.LinkedList$ListItr.next(LinkedList.java:888)
at org.glassfish.jersey.internal.util.collection.Views$1$1.next(Views.java:96)
at org.glassfish.jersey.message.internal.HeaderUtils.asHeaderString(HeaderUtils.java:230)
at org.glassfish.jersey.message.internal.HeaderUtils.lambda$asStringHeadersSingleValue$2(HeaderUtils.java:202)
at org.glassfish.jersey.message.internal.HeaderUtils$$Lambda$108/1341461635.apply(Unknown Source)
at java.util.stream.Collectors.lambda$toMap$209(Collectors.java:1321)
at java.util.stream.Collectors$$Lambda$21/936580213.accept(Unknown Source)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at org.glassfish.jersey.message.internal.HeaderUtils.asStringHeadersSingleValue(HeaderUtils.java:200)
at org.glassfish.jersey.grizzly.connector.GrizzlyConnector.writeOutBoundHeaders(GrizzlyConnector.java:490)
at org.glassfish.jersey.grizzly.connector.GrizzlyConnector.apply(GrizzlyConnector.java:268)
at org.glassfish.jersey.client.ClientRuntime.lambda$null$3(ClientRuntime.java:183)
... 14 more
我发现很多套接字都是使用netstat打开的。它看起来每个请求都会打开一个套接字。所以一段时间之后,另一个例外将抛出如下:
javax.ws.rs.ProcessingException: Too many open files
at org.glassfish.jersey.grizzly.connector.GrizzlyConnector$2.onThrowable(GrizzlyConnector.java:318)
at com.ning.http.client.providers.grizzly.GrizzlyResponseFuture.failed(GrizzlyResponseFuture.java:159)
at org.glassfish.grizzly.impl.SafeFutureImpl.notifyCompletionHandlers(SafeFutureImpl.java:187)
at org.glassfish.grizzly.impl.SafeFutureImpl.done(SafeFutureImpl.java:277)
at org.glassfish.grizzly.impl.SafeFutureImpl$Sync.innerSetException(SafeFutureImpl.java:382)
at org.glassfish.grizzly.impl.SafeFutureImpl.failure(SafeFutureImpl.java:122)
at com.ning.http.client.providers.grizzly.GrizzlyResponseFuture.abort(GrizzlyResponseFuture.java:72)
at com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider$1.failed(GrizzlyAsyncHttpProvider.java:138)
Invocation failed.
at org.glassfish.grizzly.utils.Futures.notifyFailure(Futures.java:129)
at org.glassfish.grizzly.connectionpool.SingleEndpointPool.notifyAsyncPollersOfFailure(SingleEndpointPool.java:1182)
null
at org.glassfish.grizzly.connectionpool.SingleEndpointPool.access$1500(SingleEndpointPool.java:102)
at org.glassfish.grizzly.connectionpool.SingleEndpointPool$ConnectCompletionHandler.onFailedToConnect(SingleEndpointPool.java:1321)
at org.glassfish.grizzly.connectionpool.SingleEndpointPool$ConnectCompletionHandler.failed(SingleEndpointPool.java:1290)
at org.glassfish.grizzly.impl.ReadyFutureImpl.addCompletionHandler(ReadyFutureImpl.java:147)
at org.glassfish.grizzly.connectionpool.SingleEndpointPool.connect(SingleEndpointPool.java:1157)
at org.glassfish.grizzly.connectionpool.SingleEndpointPool.take(SingleEndpointPool.java:788)
at org.glassfish.grizzly.connectionpool.MultiEndpointPool.take(MultiEndpointPool.java:592)
at com.ning.http.client.providers.grizzly.ConnectionManager.openAsync(ConnectionManager.java:143)
at com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider.execute(GrizzlyAsyncHttpProvider.java:174)
at com.ning.http.client.AsyncHttpClient.executeRequest(AsyncHttpClient.java:506)
at org.glassfish.jersey.grizzly.connector.GrizzlyConnector.apply(GrizzlyConnector.java:274)
at org.glassfish.jersey.client.ClientRuntime.lambda$null$3(ClientRuntime.java:183)
at org.glassfish.jersey.client.ClientRuntime$$Lambda$103/694396298.run(Unknown Source)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:312)
at org.glassfish.jersey.client.ClientRuntime.lambda$createRunnableForAsyncProcessing$4(ClientRuntime.java:159)
at org.glassfish.jersey.client.ClientRuntime$$Lambda$100/1987360300.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
我没有更改系统中的最大打开文件数。我想即使我将数字更改为高值,它仍会在发送足够的请求时用完。它不是根本原因。
我想到的问题是:
1,为什么会抛出ConcurrentModificationException?
2,如何限制Grizzle打开的连接号码,可以与Jersey集成?它可能有助于摆脱上述异常。
客户端代码:
ClientConfig clientConfig = new ClientConfig();
clientConfig.connectorProvider(new GrizzlyConnectorProvider());
clientConfig.property(ClientProperties.ASYNC_THREADPOOL_SIZE, 20);
Client client = ClientBuilder.newClient(clientConfig);
client.register(JacksonJsonProvider.class);
WebTarget target = client.target(serverURI);
AsyncInvoker asyncInvoker = target.request().async();
for (int i = 0; i < 100000; i++) {
Future<Response> responseFuture = asyncInvoker.post(
Entity.entity(json, MediaType.APPLICATION_JSON),
new InvocationCallback<Response>() {
@Override
public void completed(Response response) {
ObjectMapper mapper = new ObjectMapper();
MyResponse res = response.readEntity(MyResponse.class);
String result;
try {
result = mapper.writeValueAsString(res);
System.out.println(result);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable throwable) {
System.out.println("Invocation failed.");
throwable.printStackTrace();
}
});
}
Sever代码:
@POST
@Path("testAsyncCallback")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public void handleEventReport(@Suspended final AsyncResponse asyncResponse,
JaxbBean o, @Context Request req) {
asyncResponse.register(new CompletionCallback() {
@Override
public void onComplete(Throwable throwable) {
}
});
new Thread(new Runnable() {
@Override
public void run() {
MyResponse result = veryExpensiveOperation();
asyncResponse.resume(result);
}
private MyResponse veryExpensiveOperation() {
// ... very expensive operation
ObjectMapper mapper = new ObjectMapper();
try {
String json = mapper.writeValueAsString(o);
System.out.println(json);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
MyResponse response = new MyResponse();
response.setResult(1);
return response;
}
}).start();
}
提前致谢。