发送多个异步调用时,Jersey客户端抛出ConcurrentModificationException

时间:2017-07-19 02:51:36

标签: asynchronous callback jersey grizzly

我正在尝试来自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();

  }

提前致谢。

0 个答案:

没有答案