背景:

一个中小型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. MySQL中的float和decimal类型有什么区别

    decimal 类型可以精确地表示非常大或非常精确的小数.大至 1028(正或负)以及有效位数多达 28 位的数字可以作为 decimal类型存储而不失其精确性.该类型对于必须避免舍入错误的应用程序( ...

  2. Shell命令-文件及内容处理之grep(egrep)、join

    文件及内容处理 - grep(egrep).join 1. grep(egrep):文本过滤工具 grep(egrep)命令的功能说明 grep命令是Linux系统中最重要的命令之一,其功能是从文本文 ...

  3. golang介绍

    一.golang介绍  golang是Google开发的一种 静态强类型.编译型,并发型,并具有垃圾回收功能的编程语言. 二.语言特性 1..自动垃圾回收 2.支持函数多返回值 3.并发强 三.gol ...

  4. Visualize Code with Visual Studio

    In this post, App Dev Manager Ed Tovsen spotlight the features and benefits of Code Maps in Visual S ...

  5. ORM基础之ORM介绍和基础操作

    一.ORM介绍 1.ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说,ORM是通过 ...

  6. <Android基础>(三) UI开发 Part 3 RecyclerView

    RecyclerView 1)RecyclerView的基本用法 2)横向滚动和瀑布流滚动 3)注册点击事件 3.6 强大的滚动控件 RecyclerView ListView缺点: 1.不使用技巧优 ...

  7. badboy安装及使用

    badboy下载 下载地址:http://www.badboy.com.au/download/index 直接点击[continue] badboy安装 badboy录制 默认是录制状态 访问sog ...

  8. cdq分治(hdu 5618 Jam's problem again[陌上花开]、CQOI 2011 动态逆序对、hdu 4742 Pinball Game、hdu 4456 Crowd、[HEOI2016/TJOI2016]序列、[NOI2007]货币兑换 )

    hdu 5618 Jam's problem again #include <bits/stdc++.h> #define MAXN 100010 using namespace std; ...

  9. Spring MVC 学习总结(一)——MVC概要与环境配置(IDea与Eclipse示例)

    一.MVC概要 MVC是模型(Model).视图(View).控制器(Controller)的简写,是一种软件设计规范,用一种将业务逻辑.数据.显示分离的方法组织代码,MVC主要作用是降低了视图与业务 ...

  10. SpringBoot系列: Spring支持的异常处理方式

    ===================================视图函数返回 status code 的方式===================================Spring 有 ...