当前位置: 代码迷 >> java >> 当我将jedis放入ThreadLocal时无法成功关闭
  详细解决方案

当我将jedis放入ThreadLocal时无法成功关闭

热度:24   发布时间:2023-07-26 13:51:13.0

我只想在一个线程中保留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另外

首先,当实例不是池化实例时,Jedis.close()断开连接,并在池化实例时将实例返回池中。

如果将Jedis与try-with-resources一起使用,则try语句结束时,您的Jedis实例将返回到池中。 因此,当您调用close()将实例显式返回到池中时,池会抱怨该实例正在返回两次。

到目前为止,如果您尝试自己管理池化实例,则不应将Jedis实例与try-with-resources一起使用。

  相关解决方案