我刚刚在我的代码上运行了一个分析器,我注意到我花了很多时间使用ClientBuilder.newClient()
创建新客户端。这并不奇怪,因为文档声明它是一个繁重的操作,如果可能的话你应该重用客户端。
所以我创建了一个应该管理所有客户端的简单资源池
public class SimpleClientResourcePool implements ResourcePool<Client> {
private LinkedList<Client> pool = new LinkedList<>();
@Override
public Optional get() {
if(pool.isEmpty())
return Optional.empty();
return Optional.of(pool.getFirst());
}
@Override
public void release(Client value) {
pool.addLast(value);
}
}
我就像这样使用它
Client client = clientResourcePool.get().orElseGet(ClientBuilder::newClient);
Response response = get(countryId, uri, client);
try {
///random code
} finally {
response.close();
clientResourcePool.release(client);
}
当我作为用户在本地运行时,我没有看到任何问题,但在加载期间似乎存在并发问题,我不太了解。
我收到一个似乎基于此错误的异常:
Caused by: java.lang.IllegalStateException: Connection is still allocated
at org.apache.http.util.Asserts.check(Asserts.java:34)
at org.apache.http.impl.conn.BasicHttpClientConnectionManager.getConnection(BasicHttpClientConnectionManager.java:266)
at org.apache.http.impl.conn.BasicHttpClientConnectionManager$1.get(BasicHttpClientConnectionManager.java:217)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:190)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:313)
这不是你应该如何重用客户,或者我错过了一些明显的东西?
关闭客户端似乎只会导致其他例外......
答案 0 :(得分:2)
是的,您遇到的问题肯定与您的池实施有关。我实际上在你的代码中看到至少3个问题:
SimpleClientResourcePool
不是线程安全的。对pool
集合的访问不同步。在您的情况下,Queue
也会优于LinkedList
,因此请查看并发包提供的ConcurrentLinkedQueue。Client
对象,或者在未调用release
之前根据您的需要将其移至另一个“已使用客户”集合。应用这些建议你可以从这样的事情开始:
public class SimpleClientResourcePool implements ResourcePool<Client> {
private final Queue<Client> pool = new ConcurrentLinkedQueue<>();
@Override
public Optional get() {
return Optional.ofNullable(pool.poll());
}
@Override
public void release(Client value) {
pool.offer(value);
}
}
希望它有所帮助!