问题描述
我只想在一个线程中保留jedis的一个实例,所以我写了一个引用HibernateSessionFactory的类。
public class JedisFactory {
private static final ThreadLocal<Jedis> threadLocal = new ThreadLocal<Jedis>();
private static JedisPool pool;
static {
try {
Long timestampPre = System.currentTimeMillis();
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxWaitMillis(Constants.REDIS_MAX_WAIT_MILLIS);
config.setMinIdle(Constants.REDIS_MIN_IDLE);
config.setMaxIdle(Constants.REDIS_MAX_IDLE);
config.setMaxTotal(Constants.REDIS_MAX_ACTIVE);
pool = new JedisPool(config, Constants.REDIS_ADDRESS, Constants.REDIS_PORT, Constants.REDIS_TIMEOUT);
System.out.println("TEST createJedisPool: " + (System.currentTimeMillis() - timestampPre));
} catch (Exception e) {
System.err.println("%%%% Error Creating JedisFactory %%%%");
e.printStackTrace();
}
}
private JedisFactory() {
}
public static Jedis getJedis() throws JedisConnectionException {
Jedis jedis = (Jedis) threadLocal.get();
if (jedis == null) {
if (pool == null) {
rebuildJedisPool();
}
jedis = (pool != null)
? pool.getResource()
: null;
if (jedis != null) jedis.auth(Constants.REDIS_AUTH);
threadLocal.set(jedis);
}
if (!jedis.isConnected()) {
System.out.println(System.currentTimeMillis() + "open jedis");
jedis.connect();
}
return jedis;
}
/**
* Rebuild jedis factory
*
*/
public static void rebuildJedisPool() {
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxWaitMillis(Constants.REDIS_MAX_WAIT_MILLIS);
config.setMinIdle(Constants.REDIS_MIN_IDLE);
config.setMaxIdle(Constants.REDIS_MAX_IDLE);
config.setMaxTotal(Constants.REDIS_MAX_ACTIVE);
// 创建连接池
pool = new JedisPool(config, Constants.REDIS_ADDRESS, Constants.REDIS_PORT, Constants.REDIS_TIMEOUT);
} catch (Exception e) {
System.err.println("%%%% Error Creating JedisFactory %%%%");
e.printStackTrace();
}
}
/**
* Close the single jedis instance.
*
*/
public static void closeJedis() {
Jedis jedis = (Jedis) threadLocal.get();
threadLocal.set(null);
if (jedis != null) {
jedis.close();
}
}
}
它确实在一个线程中保留了一个jedis实例,并且可以正常工作,但是当我想通过调用closeJedis()来克隆jedis时,它将抛出异常。 这是下面的异常信息:
[详细信息] redis.clients.jedis.exceptions.JedisException:无法将资源返回到redis.clients.jedis.JedisPool.returnResource(JedisPool)上redis.clients.jedis.JedisPool.returnResource(JedisPool.java:114)的池中.java:1)位于com.lingxia.yueju.data.cache.AdCacheImpl.getAdByCity(AdCacheImpl.java:87)的redis.clients.jedis.Jedis.close(Jedis.java:3306)。 data.service.AdServiceImpl.getAdByCity(AdServiceImpl.java:172)位于com.lingxia.yueju.app.controller.AdController.getBanner(AdController.java:50)位于sun.reflect.NativeMethodAccessorImpl.invoke0(本地方法)。在org.springframework.web上的java.lang.reflect.Method.invoke(Method.java:483)上的sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)上的reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) org.springframework.web.servlet.mvc.annotation.AnnotationMethod上的.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175) org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java: 943)在org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)在org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)在org.springframework.web.servlet.FrameworkServlet位于javax.servlet.http.HttpServlet.service(HttpServlet.java:618)的org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)的.doGet(FrameworkServlet.java:852)。 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)上的http.HttpServlet.service(HttpServlet.java:725)org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)上的在org.apache.tomcat.web org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)处的socket.server.WsFilter.doFilter(WsFilter.java:52)在org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java: 206)在org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)在org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)在org.apache.catalina.authenticator.AuthenticatorBase org.org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)的org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)的.invoke(AuthenticatorBase.java:501)。 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)处的apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)在org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter。 java:537),网址为org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11P rocessor.java:1085),位于org.apache.coyote.AbstractProtocol $ AbstractConnectionHandler.process(AbstractProtocol.java:658),位于org.apache.coyote.http11.Http11AprProtocol $ Http11ConnectionHandler.process(Http11AprProtocol.java:277) org.apache.tomcat.util.net.AprEndpoint $ SocketProcessor.run(AprEndpoint.java:2396)的.tomcat.util.net.AprEndpoint $ SocketProcessor.doRun(AprEndpoint.java:2407)在java.util.concurrent.ThreadPoolExecutor .runWorker(ThreadPoolExecutor.java:1142)(位于java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:617)位于org.apache.tomcat.util.threads.TaskThread $ WrappingRunnable.run(TaskThread.java:61) ),位于java.lang.Thread.run(Thread.java:745),原因是:redis.clients.jedis.exceptions.JedisException:无法将资源返回到redis.clients.util.Pool.returnResourceObject(Pool。 java:61)在redis.clients.jedis.JedisPool.returnResource(JedisPool.java:111)... 41更多原因:java.lang.IllegalStateException:对象已经存在 已移至该池或在org.apache.commons.pool2.impl.GenericObjectPool.returnObject(GenericObjectPool.java:582)处无效,位于redis.clients.util.Pool.returnResourceObject(Pool.java:59)... 42另外
1楼
首先,当实例不是池化实例时,Jedis.close()断开连接,并在池化实例时将实例返回池中。
如果将Jedis与try-with-resources一起使用,则try语句结束时,您的Jedis实例将返回到池中。 因此,当您调用close()将实例显式返回到池中时,池会抱怨该实例正在返回两次。
到目前为止,如果您尝试自己管理池化实例,则不应将Jedis实例与try-with-resources一起使用。