背景:

一个中小型H5游戏

核心错误信息:

  (1): java.lang.ClassCastException: [B cannot be cast to java.lang.Long

  at redis.clients.jedis.Connection.getIntegerReply(Connection.java:201)
  at redis.clients.jedis.Jedis.del(Jedis.java:129) 

 

  (2):redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Socket closed

  at redis.clients.jedis.Protocol.process(Protocol.java:131)
  at redis.clients.jedis.Protocol.read(Protocol.java:187)
  at redis.clients.jedis.Connection.getIntegerReply(Connection.java:201)
  at redis.clients.jedis.Jedis.del(Jedis.java:129)

贴上核心问题代码(Jedis工具类):

/**
* 获取连接池.
*
* @return 连接池实例
*/
private static JedisPool getPool() {
String key = ip + ":" + port;
JedisPool pool = null;
//这里为了提供大多数情况下线程池Map里面已经有对应ip的线程池直接返回,提高效率
if (maps.containsKey(key)) {
pool = maps.get(key);
return pool;
}
//这里的同步代码块防止多个线程同时产生多个相同的ip线程池
synchronized (JedisUtil.class) {
if (!maps.containsKey(key)) {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxIdle(maxIdle);
config.setTestOnBorrow(true);
config.setTestOnReturn(true);
config.setMaxWaitMillis(maxWaitMillis);
config.setBlockWhenExhausted(blockWhenExhausted);
try {
if (password != null && !"".equals(password)) {
pool = new JedisPool(config, ip, port, timeout, password);
} else {
pool = new JedisPool(config, ip, port, timeout);
}
maps.put(key, pool);
} catch (Exception e) {
e.printStackTrace();
}
} else {
pool = maps.get(key);
}
}
return pool;
} /**
* 获取Redis实例.
*
* @return Redis工具类实例
*/
public Jedis getJedis() {
Jedis jedis = null;
int count = 0;
while (jedis == null && count < retryNum) {
try {
JedisPool pool = getPool();
jedis = pool.getResource();
} catch (Exception e) {
logger.error("get redis master failed!", e);
} finally {
closeJedis(jedis);
}
count++;
}
return jedis;
} /**
* 释放redis实例到连接池.
*
* @param jedis redis实例
*/
public void closeJedis(Jedis jedis) {
if (jedis != null) {
getPool().returnResource(jedis);
}
}

  

问题剖析:

  查阅了线上资料,发现是由于多线程使用了同一个Jedis实例导致的并发问题.

结果:

  一开始,我发现我调用了getJedis()获取了jedis实例并使用后没有关闭.

  于是我把关闭Jedis的操作加上去了

  结果是错误的量少了

  但还是有报错,说明这是其中一个问题.

  最后还是没能使用Jedis连接池搞定这个问题

解决办法:

  抛弃使用连接池

  每次使用Jedis都生成一个独立的实例

  每次用完以后就close()

  这样也就不存在并发的问题了

  这样做有一个潜在的问题是如果并发量达到很大值,Redis连接数被塞满的话还是会出现问题.

  一般情况下不是非常大的并发,用完就close的话,没那么容易到这个瓶颈

相关代码:

    /**
* 获取一个独立的Jedis实例
* @return jedis
*/
public Jedis getSingleJedis() {
Jedis jedis = new Jedis(ip, port, timeout);
jedis.connect();
if (StringUtils.isNotBlank(password)) {
jedis.auth(password);
}
return jedis;
}   // 关闭Jedis直接调用 jedis.close() 即可

  

Java中多线程服务中遇到的Redis并发问题?的更多相关文章

  1. WIN7中组件服务中的DCOM配置找不到Microsoft Excel应用程序的解决办法

    转自:http://blog.csdn.net/lploveme/article/details/8215265 在运行栏中输入命令:dcomcnfg,打开组件服务管理窗口,但是却发现找不到Micro ...

  2. GDAL库中WFS服务中含有中文不能获取数据的问题

    GDAL库中目前提供了对WFS服务发布的数据进行获取,目前发现对于中文的服务名称或者图层名为中文,GDAL不能正确识别.通过调试发现,其原因有下面两点: 1.输入的URL路径没有使用UTF8编码而从网 ...

  3. geoserver中WMS服务详细说明

    官方geoserver中WMS服务中几种操作的API的详细说明地址: http://docs.geoserver.org/stable/en/user/services/wms/reference.h ...

  4. Java中多线程并发体系知识点汇总

    一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种 ...

  5. 2.1多线程(java学习笔记) java中多线程的实现(附静态代理模式)

    一.多线程 首先我们要清楚程序.进程.线程的关系. 首先进程从属于程序,线程从属于进程. 程序指计算机执行操作或任务的指令集合,是一个静态的概念. 但我们实际运行程序时,并发程序因为相互制约,具有“执 ...

  6. Java 在spring cloud中使用Redis,spring boot同样适用

    1.本地安装redis服务,官网下载. 2.在开发中要使用redis,首先要启动本地redis服务,启动后页面如下: 3.在spring boot项目pom.xml文件中添加Redis需要的依赖包,可 ...

  7. 庐山真面目之十三微服务架构中如何在Docker上使用Redis缓存

    一.介绍     1.开始说明 在微服务器架构中,有一个组件是不能少的,那就是缓存组件.其实来说,缓存组件,这个叫法不是完全正确,因为除了缓存功能,它还能完成其他很多功能.我就不隐瞒了,今天我们要探讨 ...

  8. 利用Java Service Wrapper将java项目添加到windows服务中

    1.web项目,即tomcat/resin添加至window系统服务,步骤如下:第一步:找到tomcat的bin目录,如:D:\apache-tomcat-8.0.26\bin第二步:打开cmd,cd ...

  9. Java程序员面试中的多线程问题

    很多核心Java面试题来源于多线程(Multi-Threading)和集合框架(Collections Framework),理解核心线程概念时,娴熟的实际经验是必需的.这篇文章收集了Java线程方面 ...

随机推荐

  1. react混合开发APP,资源分享

    第一个: 链接:https://pan.baidu.com/s/1KdIs8EUcB9YTuK9VW1dC7g 密码:b68m 第二个: 链接:https://pan.baidu.com/s/1mi7 ...

  2. U盘安装CentOS系统、raid5制作以及nohup的使用

    最近折腾服务器,用U盘安装了系统,总结了一些避坑措施: 下载UltraISO工具,用来刻盘 从centos官网下载ISO镜像,然后刻盘 关键是在你进入系统安装界面后,如下: 选中第一项,按tab键(看 ...

  3. J2SE学习笔记

    如何学习Java 一.面向对象设计思想 1.面向对象:开车去新疆,车怎么去的我不管,我只调用车的go() 方法即可. 2.类和对象:类可以看成一类对象的模板,对象可以看成该类的一个具体实例. 3.类和 ...

  4. UOJ10 UTR #1 pyx的难题(堆)

    显然优先级越高完成的越早,二分答案后用堆模拟就是O(nlog2n)的.考虑去一个log.先固定特殊题的优先级为最低,模拟一遍.这样在特殊题被扔过来到T的这段时间内,如果将特殊题的优先级提高至超过这其中 ...

  5. kafka partition(分区)与 group

    kafka partition(分区)与 group   一. 1.原理图 2.原理描述 一个topic 可以配置几个partition,produce发送的消息分发到不同的partition中,co ...

  6. CMDB服务器管理系统【s5day90】:创建资产更新服务器硬盘信息

    1.创建硬件资产信息 import json from django.shortcuts import render,HttpResponse from django.views.decorators ...

  7. Java小知识点总结

    目录 配置 数据库配置文件 基础知识 Switch i++和++i 快捷打代码 输入数据 代码折叠 super关键字 instanceof 防止类型强制转换带来的错误 继承 第一个Java程序 Jav ...

  8. 轴对称 Navier-Stokes 方程组的点态正则性准则 I

    在 [Lei, Zhen; Zhang, Qi. Criticality of the axially symmetric Navier-Stokes equations. Pacific J. Ma ...

  9. [再寄小读者之数学篇](2014-10-08 乘积型 Sobolev 不等式)

    $$\bex n\geq 2, 1\leq p<n\ra \sen{f}_{L^\frac{np}{n-p}(\bbR^n)} \leq C\prod_{k=1}^n \sen{\p_k f}_ ...

  10. LinQ简单增、删、改、查

    一.简单介绍 1.LinQ to Sql类(NET Language Integrated Query (LINQ) ) LINQ定义了大约40个查询操作符,如select.from.in.where ...