• Redis学习记录(六)redis客户端jedis多线程操作时报异常


      jedis不是线程安全的:

    public class RedisLockTest {
    
        private Integer inventory = 1000;
        private int num  = 1000;
        private int corePoolsize = 100;
        private int maximumPoolSize = 1000;
        private long keepAliveTime = 10000;
        private LinkedBlockingDeque linkedBlockingDeque = new LinkedBlockingDeque();
    
       /**
         * jedis--redis客户端,在多线程操作时会报异常
         * @throws InterruptedException
         */
        @Test
        public void redismethodError() throws InterruptedException {
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolsize,maximumPoolSize,keepAliveTime,
                    java.util.concurrent.TimeUnit.SECONDS,linkedBlockingDeque);
            num =20;
            CountDownLatch countDownLatch = new CountDownLatch(num);
            Jedis jedis = new Jedis("localhost",6379);
            jedis.auth("root123456");
            for (int i = 0; i < num; i++) {
                threadPoolExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        try{
                            jedis.set("aaa","value");
                        }catch (Exception e){
                            System.out.println(e);
                        }finally {
                            countDownLatch.countDown();
                        }
                    }
                });
            }
            countDownLatch.await();
            threadPoolExecutor.shutdown();
        }
    }
    

      该程序可能会报异常:

        1、redis.clients.jedis.exceptions.JedisDataException: ERR Protocol error: expected '$', got ' '

        2、redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Connection reset

        3、redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Connection reset by peer: socket write error

        4、 redis.clients.jedis.exceptions.JedisDataException: RR Protocol error: invalid bulk length

      打印出错误栈:

    Exception in thread "pool-1-thread-7" Exception in thread "pool-1-thread-10" redis.clients.jedis.exceptions.JedisDataException: RR Protocol error: invalid bulk length
    	at redis.clients.jedis.Protocol.processError(Protocol.java:127)
    	at redis.clients.jedis.Protocol.process(Protocol.java:161)
    	at redis.clients.jedis.Protocol.read(Protocol.java:215)
    	at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)
    	at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:239)
    	at redis.clients.jedis.Jedis.set(Jedis.java:121)
    	at com.yhq.redis.RedisLockTest$2.run(RedisLockTest.java:76)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    	at java.lang.Thread.run(Thread.java:748)
    

      这种报错是因为客户端向redis发送的命令,redis发现接收的命令不满足RESP协议(Redis服务器与客户端通过RESP(REdis Serialization Protocol)协议通信)返回以字节 "-"开头的字节流,客户端jedis接收到后,抛出异常。

      在 RESP 中, 一些数据的类型通过它的第一个字节进行判断:

        单行回复:回复的第一个字节是 "+"

        错误信息:回复的第一个字节是 "-"

        整形数字:回复的第一个字节是 ":"

        多行字符串:回复的第一个字节是 "$"

        数组:回复的第一个字节是 "*" 

    public final class Protocol {
      public static final byte DOLLAR_BYTE = '$';
      public static final byte ASTERISK_BYTE = '*';
      public static final byte PLUS_BYTE = '+';
      public static final byte MINUS_BYTE = '-';
      public static final byte COLON_BYTE = ':';
    }
    

      分析命令不满足RESP协议的原因:

      jedis.set("aaa","value");    ---->   client.set(key, value);    ----->

    public class Connection implements Closeable {
    
      private RedisOutputStream outputStream;
      private RedisInputStream inputStream;
    
      protected Connection sendCommand(final Command cmd, final byte[]... args) {
        try {
          //获取连接
          connect();
          //发送命令(向outputStream写入拼接的命令,但是没有执行输出流刷新,redis还接收不到命令)
          Protocol.sendCommand(outputStream, cmd, args);
          pipelinedCommands++;
          return this;
        } catch (JedisConnectionException ex) {
               //......................
          }
          broken = true;
          throw ex;
        }
     }    
    

      ------>

    public final class Protocol {
      private static void sendCommand(final RedisOutputStream os, final byte[] command,
          final byte[]... args) {
        try {
          os.write(ASTERISK_BYTE);
          os.writeIntCrLf(args.length + 1);
          os.write(DOLLAR_BYTE);
          os.writeIntCrLf(command.length);
          os.write(command);
          os.writeCrLf();
          // 如果一个线程刚执行到这里,另一个线程执行到 outputStream.flush();操作,那么就报该异常
          for (final byte[] arg : args) {
            os.write(DOLLAR_BYTE);
            os.writeIntCrLf(arg.length);
            os.write(arg);
            os.writeCrLf();
          }
        } catch (IOException e) {
          throw new JedisConnectionException(e);
        }
      }
    }
    

      

  • 相关阅读:
    【已解决】ERR_BLOCKED_BY_XSS_AUDITOR:Chrome 在此网页上检测到了异常代码:解决办法
    【已解决】Microsoft visual c++ 14.0 is required问题解决办法
    爬虫处理网站的bug---小于号未转化为实体符
    pymysql 在数据库中插入空值
    python 正则括号的使用及踩坑
    pymysql 解决 sql 注入问题
    python3 操作MYSQL实例及异常信息处理--用traceback模块
    LeetCode 837. 新21点 | Python
    LeetCode 面试题64. 求1+2+…+n | Python
    LeetCode 101. 对称二叉树 | Python
  • 原文地址:https://www.cnblogs.com/yaohuiqin/p/12765917.html
Copyright © 2020-2023  润新知