zoukankan      html  css  js  c++  java
  • Redis:解决分布式高并发修改同一个Key的问题

    Redis:解决分布式高并发修改同一个Key的问题

    本篇文章是通过watch(监控)+mutil(事务)实现应用于在分布式高并发处理等相关场景。下边先通过redis-cli.exe来测试多个线程修改时,遇到问题及解决问题。

    高并发下修改同一个key遇到的问题:

    1)定义一个hash类型的key,key为:lock_test,元素locker的值初始化为0。

    2)实现高并发下对locker元素的值递增:定义64个多线程,并发的对lock_test元素locker的值进行修改。

    复制代码
    package com.dx.es;
    

    import java.util.concurrent.CountDownLatch;

    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;

    public class Test_UnLock {
    public static void main(String[] args) {
    final JedisPool pool = RedisUtil.getPool();

        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 获得jedis对象</span>
        Jedis jedis =<span style="color: #000000;"> pool.getResource();
        jedis.hset(</span>"lock_test", "locker", "0"<span style="color: #000000;">);
        String val </span>= jedis.hget("lock_test", "locker"<span style="color: #000000;">);
        System.out.println(</span>"lock_test.locker的初始值為:" +<span style="color: #000000;"> val);
        jedis.close();
    
        </span><span style="color: #0000ff;">int</span> threahSize = 64<span style="color: #000000;">;
        </span><span style="color: #0000ff;">final</span> CountDownLatch threadsCountDownLatch = <span style="color: #0000ff;">new</span><span style="color: #000000;"> CountDownLatch(threahSize);
    
        Runnable handler </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> Runnable() {
            </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() {
                Jedis jedis </span>=<span style="color: #000000;"> pool.getResource();
    
                Integer integer </span>= Integer.valueOf(jedis.hget("lock_test", "locker"<span style="color: #000000;">));
                jedis.hset(</span>"lock_test", "locker", String.valueOf(integer + 1<span style="color: #000000;">));
    
                jedis.close();
                threadsCountDownLatch.countDown();
            }
        };
    
        </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; threahSize; i++<span style="color: #000000;">) {
            </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> Thread(handler).start();
        }
    
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 等待所有并行子线程任务完成。</span>
        <span style="color: #0000ff;">try</span><span style="color: #000000;"> {
            threadsCountDownLatch.await();
        } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
            e.printStackTrace();
        }
    
        System.out.println(</span>"complete"<span style="color: #000000;">);
    
        val </span>= jedis.hget("lock_test", "locker"<span style="color: #000000;">);
        System.out.println(val);
    }
    

    }

    复制代码

    RedisUtil.java

    复制代码
    package com.dx.es;
    

    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;

    public class RedisUtil {
    public static JedisPool getPool() {
    // 简单创建 Jedis的方法:
    // final Jedis jedis = new Jedis("127.0.0.1",6379);

        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 下边使用线程池的方案:jedis对象是线程不安全的,因此在并发情况下要使用JedisPool,默认情况下jedisPool只支持8个连接,因此在声明JedisPool时要先修改JedisPool的最大连接数</span>
        JedisPoolConfig config = <span style="color: #0000ff;">new</span><span style="color: #000000;"> JedisPoolConfig();
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 修改最大连接数</span>
        config.setMaxTotal(32<span style="color: #000000;">);
        
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 声明一个线程池</span>
        JedisPool pool = <span style="color: #0000ff;">new</span> JedisPool(config, "127.0.0.1", 6379<span style="color: #000000;">);
    
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> pool;
    }
    

    }

    复制代码

    此时,会出现以下问题:

    1. A线程获取key的值为0,而B线程也获取jkey的值0,则A把key值递增为1,B线程也实现把key值递增为1。两个线程都执行了key值修改:0到1。
    2. 在1)中最终key修改为了1,但是c线程获取key的值为0(因为c线程读取key值时,a、b线程还未触发修改,因此c线程读取到的值为0),此时d线程读取到的值为1(因为d线程读取key值时,a、b线程已触发修改,一次d线程取到的值为1)。
    3. 此时假设d线程优先触发递增,则在c线程未触发提交之前d线程已经把值修改了2,但是c此时并不知道在它获取到值到修改之前这段时间发生了什么,直接把值修改1。

    此时执行打印结果为:

    lock_test.locker的初始值為:0
    complete
    24 #备注:也可能是其他值,可能是正确值64的可能性比较小。

    通过watch+mutil解决并发修改的问题:

    需要掌握Redis 事务命令:

    下表列出了 redis 事务的相关命令:

    序号 命令 描述 可用版本
     1  DISCARD

    Redis Discard 命令用于取消事务,放弃执行事务块内的所有命令。

    语法 redis Discard 命令基本语法如下:

    redis 127.0.0.1:6379> DISCARD
     >= 2.0.0
     2  EXEC

    Redis Exec 命令用于执行所有事务块内的命令。

    语法 redis Exec 命令基本语法如下:

    redis 127.0.0.1:6379>Exec
     >= 1.2.0
     3  MULTI

    Redis Multi 命令用于标记一个事务块的开始。

    事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行。

    语法 redis Multi 命令基本语法如下:

    redis 127.0.0.1:6379>Multi
     >= 1.2.0
     4  UNWATCH

    Redis Unwatch 命令用于取消 WATCH 命令对所有 key 的监视。

    语法 redis Unwatch 命令基本语法如下:

    redis 127.0.0.1:6379> UNWATCH 
     >= 2.2.0
     5  WATCH

    Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断

    语法 redis Watch 命令基本语法如下:

    WATCH key [key ...]
     >= 2.2.0

     Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:

    • 批量操作在发送 EXEC 命令前被放入队列缓存。
    • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
    • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

    一个事务从开始到执行会经历以下三个阶段:

    • 开始事务。
    • 命令入队。
    • 执行事务。

    备注:概念性摘自《http://www.runoob.com/redis/redis-transactions.html》

    redis-cli.exe下的事务操作:

    复制代码
    # 事务被成功执行
    redis 127.0.0.1:6379> MULTI
    OK
    

    redis 127.0.0.1:6379> INCR user_id
    QUEUED

    redis 127.0.0.1:6379> INCR user_id
    QUEUED

    redis 127.0.0.1:6379> INCR user_id
    QUEUED

    redis 127.0.0.1:6379> PING
    QUEUED

    redis 127.0.0.1:6379> EXEC
    1) (integer) 1
    2) (integer) 2
    3) (integer) 3
    4) PONG

    复制代码

    并发情况下使用watch+mutil操作:

    事务块内所有命令的返回值,按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil 。

    A线程:

    复制代码
    # 监视 key ,且事务成功执行
    redis 127.0.0.1:6379> WATCH lock lock_times
    OK
    

    redis 127.0.0.1:6379> MULTI
    OK

    redis 127.0.0.1:6379> SET lock "huangz"
    QUEUED

    redis 127.0.0.1:6379> INCR lock_times
    QUEUED

    redis 127.0.0.1:6379> EXEC
    1) OK
    2) (integer) 1

    复制代码

    B线程:

    复制代码
    # 监视 key ,且事务被打断
    redis 127.0.0.1:6379> WATCH lock lock_times
    OK
    

    redis 127.0.0.1:6379> MULTI
    OK

    redis 127.0.0.1:6379> SET lock "joe" # 就在这时,另一个客户端修改了 lock_times 的值
    QUEUED

    redis 127.0.0.1:6379> INCR lock_times
    QUEUED

    redis 127.0.0.1:6379> EXEC # 因为 lock_times 被修改, joe 的事务执行失败
    (nil)

    复制代码

    上边演示了A、B线程并发下的watch+mutil操作情况。

    解决高并发下修改同一个key遇到的问题:

    复制代码
    package com.dx.es;
    

    import java.util.List;
    import java.util.concurrent.CountDownLatch;

    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.Transaction;

    public class Test_Lock3 {
    public static void main(String[] args) {
    final JedisPool pool = RedisUtil.getPool();

        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 对测试key赋初始值</span>
        Jedis jedis =<span style="color: #000000;"> pool.getResource();
        jedis.hset(</span>"lock_test", "locker", "0"<span style="color: #000000;">);
        String val </span>= jedis.hget("lock_test", "locker"<span style="color: #000000;">);
        System.out.println(</span>"lock_test.locker的初始值為:" +<span style="color: #000000;"> val);
        jedis.close();
    
        </span><span style="color: #0000ff;">int</span> threahSize = 64<span style="color: #000000;">;
        </span><span style="color: #0000ff;">final</span> CountDownLatch threadsCountDownLatch = <span style="color: #0000ff;">new</span><span style="color: #000000;"> CountDownLatch(threahSize);
    
        Runnable handler </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> Runnable() {
            </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() {
                Jedis jedis </span>=<span style="color: #000000;"> pool.getResource();
    
                </span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">) {
                    jedis.watch(</span>"lock_test"<span style="color: #000000;">);
                    String val </span>= jedis.hget("lock_test", "locker"<span style="color: #000000;">);
                    Integer integer </span>=<span style="color: #000000;"> Integer.valueOf(val);
                    Transaction tx </span>=<span style="color: #000000;"> jedis.multi();
    
                    tx.hset(</span>"lock_test", "locker", String.valueOf(integer + 1<span style="color: #000000;">));
    
                    List</span>&lt;Object&gt; exec =<span style="color: #000000;"> tx.exec();
    
                    </span><span style="color: #0000ff;">if</span> (exec == <span style="color: #0000ff;">null</span> ||<span style="color: #000000;"> exec.isEmpty()) {
                        System.out.println(Thread.currentThread().getName() </span>+ ":" + "Error:(" + val + "=&gt;" + (integer + 1) + ")"<span style="color: #000000;">);
                    } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
                        String values </span>= ""<span style="color: #000000;">;
                        </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; exec.size(); i++<span style="color: #000000;">) {
                            values </span>+=<span style="color: #000000;"> exec.get(i).toString();
                        }
                        System.out.println(Thread.currentThread().getName() </span>+ ":" + values + ":(" + val + "=&gt;" + (integer + 1) + ")"<span style="color: #000000;">);
                        </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;
                    }
    
                    </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                        Thread.sleep(</span>10<span style="color: #000000;">);
                    } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                jedis.close();
                threadsCountDownLatch.countDown();
            }
        };
    
        </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; threahSize; i++<span style="color: #000000;">) {
            </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> Thread(handler).start();
        }
    
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 等待所有并行子线程任务完成。</span>
        <span style="color: #0000ff;">try</span><span style="color: #000000;"> {
            threadsCountDownLatch.await();
        } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
            e.printStackTrace();
        }
    
        System.out.println(</span>"complete"<span style="color: #000000;">);
    
        val </span>= jedis.hget("lock_test", "locker"<span style="color: #000000;">);
        System.out.println(val);
    }
    

    }

    复制代码

    打印结果:

    复制代码
    lock_test.locker的初始值為:0
    Thread-8:0:(0=>1)
    Thread-56:Error:(1=>2)
    Thread-53:0:(1=>2)
    Thread-25:Error:(0=>1)
    Thread-18:Error:(0=>1)
    Thread-3:Error:(0=>1)
    Thread-30:Error:(2=>3)
    Thread-11:Error:(2=>3)
    Thread-9:Error:(0=>1)
    Thread-63:0:(2=>3)
    Thread-7:Error:(0=>1)
    Thread-10:0:(3=>4)
    Thread-34:0:(4=>5)
    Thread-65:Error:(4=>5)
    Thread-24:Error:(0=>1)
    Thread-17:Error:(0=>1)
    Thread-62:0:(5=>6)
    Thread-29:Error:(6=>7)
    Thread-61:0:(6=>7)
    Thread-64:0:(7=>8)
    Thread-16:Error:(0=>1)
    Thread-19:Error:(8=>9)
    Thread-6:Error:(0=>1)
    Thread-28:Error:(0=>1)
    Thread-21:Error:(0=>1)
    Thread-14:Error:(0=>1)
    Thread-20:Error:(0=>1)
    Thread-5:Error:(0=>1)
    Thread-13:Error:(0=>1)
    Thread-15:Error:(0=>1)
    Thread-22:Error:(0=>1)
    Thread-4:Error:(0=>1)
    Thread-12:Error:(0=>1)
    Thread-23:Error:(0=>1)
    Thread-54:Error:(0=>1)
    Thread-57:Error:(0=>1)
    Thread-26:0:(8=>9)
    Thread-27:Error:(8=>9)
    Thread-32:Error:(9=>10)
    Thread-35:Error:(9=>10)
    Thread-56:0:(9=>10)
    Thread-33:Error:(10=>11)
    Thread-50:0:(10=>11)
    Thread-31:0:(11=>12)
    Thread-38:0:(12=>13)
    Thread-25:Error:(13=>14)
    Thread-36:0:(13=>14)
    Thread-39:Error:(14=>15)
    Thread-14:0:(14=>15)
    Thread-19:Error:(14=>15)
    Thread-17:Error:(14=>15)
    Thread-6:Error:(14=>15)
    Thread-9:Error:(14=>15)
    Thread-33:Error:(14=>15)
    Thread-35:Error:(14=>15)
    Thread-23:Error:(14=>15)
    Thread-18:Error:(14=>15)
    Thread-15:Error:(14=>15)
    Thread-11:Error:(14=>15)
    Thread-7:Error:(14=>15)
    Thread-57:Error:(14=>15)
    Thread-27:Error:(14=>15)
    Thread-16:Error:(14=>15)
    Thread-65:Error:(14=>15)
    Thread-24:Error:(14=>15)
    Thread-13:Error:(14=>15)
    Thread-32:Error:(15=>16)
    Thread-28:Error:(14=>15)
    Thread-21:Error:(14=>15)
    Thread-30:Error:(14=>15)
    Thread-54:Error:(14=>15)
    Thread-22:Error:(14=>15)
    Thread-25:Error:(14=>15)
    Thread-3:Error:(14=>15)
    Thread-29:Error:(14=>15)
    Thread-5:Error:(14=>15)
    Thread-12:Error:(14=>15)
    Thread-20:Error:(14=>15)
    Thread-40:0:(15=>16)
    Thread-4:Error:(14=>15)
    Thread-41:0:(16=>17)
    Thread-44:0:(17=>18)
    Thread-45:0:(18=>19)
    Thread-47:0:(19=>20)
    Thread-43:0:(20=>21)
    Thread-48:0:(21=>22)
    Thread-37:0:(22=>23)
    Thread-49:0:(23=>24)
    Thread-55:0:(24=>25)
    Thread-60:0:(25=>26)
    Thread-42:0:(26=>27)
    Thread-52:0:(27=>28)
    Thread-46:0:(28=>29)
    Thread-58:0:(29=>30)
    Thread-51:0:(30=>31)
    Thread-66:0:(31=>32)
    Thread-59:0:(32=>33)
    Thread-17:0:(33=>34)
    Thread-19:Error:(33=>34)
    Thread-39:Error:(33=>34)
    Thread-28:0:(34=>35)
    Thread-54:Error:(34=>35)
    Thread-65:Error:(34=>35)
    Thread-25:Error:(34=>35)
    Thread-30:Error:(34=>35)
    Thread-5:Error:(35=>36)
    Thread-13:Error:(35=>36)
    Thread-16:Error:(34=>35)
    Thread-6:Error:(34=>35)
    Thread-9:Error:(34=>35)
    Thread-21:Error:(35=>36)
    Thread-29:Error:(35=>36)
    Thread-33:Error:(34=>35)
    Thread-57:Error:(35=>36)
    Thread-24:Error:(34=>35)
    Thread-22:Error:(34=>35)
    Thread-32:Error:(35=>36)
    Thread-23:Error:(34=>35)
    Thread-7:Error:(34=>35)
    Thread-15:Error:(34=>35)
    Thread-4:0:(35=>36)
    Thread-20:Error:(35=>36)
    Thread-12:Error:(35=>36)
    Thread-35:0:(36=>37)
    Thread-18:Error:(36=>37)
    Thread-11:Error:(36=>37)
    Thread-3:Error:(36=>37)
    Thread-27:Error:(37=>38)
    Thread-39:Error:(37=>38)
    Thread-19:0:(37=>38)
    Thread-7:Error:(38=>39)
    Thread-33:0:(38=>39)
    Thread-29:Error:(38=>39)
    Thread-16:Error:(38=>39)
    Thread-22:Error:(38=>39)
    Thread-65:Error:(38=>39)
    Thread-54:Error:(38=>39)
    Thread-57:Error:(38=>39)
    Thread-30:Error:(38=>39)
    Thread-21:Error:(38=>39)
    Thread-24:Error:(38=>39)
    Thread-32:Error:(39=>40)
    Thread-5:Error:(39=>40)
    Thread-13:Error:(39=>40)
    Thread-6:Error:(38=>39)
    Thread-25:Error:(38=>39)
    Thread-9:Error:(38=>39)
    Thread-20:0:(39=>40)
    Thread-12:Error:(39=>40)
    Thread-15:Error:(38=>39)
    Thread-23:Error:(38=>39)
    Thread-18:Error:(40=>41)
    Thread-3:Error:(40=>41)
    Thread-27:0:(40=>41)
    Thread-11:Error:(40=>41)
    Thread-39:0:(41=>42)
    Thread-7:Error:(42=>43)
    Thread-54:0:(42=>43)
    Thread-22:Error:(42=>43)
    Thread-30:Error:(42=>43)
    Thread-57:Error:(42=>43)
    Thread-65:Error:(42=>43)
    Thread-32:Error:(43=>44)
    Thread-24:Error:(43=>44)
    Thread-5:Error:(42=>43)
    Thread-21:Error:(42=>43)
    Thread-16:Error:(43=>44)
    Thread-29:Error:(43=>44)
    Thread-6:0:(43=>44)
    Thread-9:Error:(43=>44)
    Thread-23:Error:(43=>44)
    Thread-25:Error:(43=>44)
    Thread-15:Error:(43=>44)
    Thread-12:Error:(43=>44)
    Thread-13:Error:(44=>45)
    Thread-11:0:(44=>45)
    Thread-18:Error:(44=>45)
    Thread-3:Error:(44=>45)
    Thread-57:0:(45=>46)
    Thread-7:Error:(45=>46)
    Thread-22:Error:(45=>46)
    Thread-30:Error:(45=>46)
    Thread-9:0:(46=>47)
    Thread-65:Error:(46=>47)
    Thread-25:Error:(46=>47)
    Thread-24:Error:(46=>47)
    Thread-21:Error:(47=>48)
    Thread-32:Error:(47=>48)
    Thread-5:Error:(47=>48)
    Thread-15:Error:(47=>48)
    Thread-16:0:(47=>48)
    Thread-29:Error:(47=>48)
    Thread-12:Error:(48=>49)
    Thread-23:Error:(47=>48)
    Thread-13:0:(48=>49)
    Thread-18:Error:(49=>50)
    Thread-3:Error:(49=>50)
    Thread-7:0:(49=>50)
    Thread-30:Error:(49=>50)
    Thread-22:Error:(49=>50)
    Thread-25:0:(50=>51)
    Thread-65:Error:(50=>51)
    Thread-12:0:(51=>52)
    Thread-21:Error:(51=>52)
    Thread-32:Error:(52=>53)
    Thread-24:Error:(52=>53)
    Thread-29:Error:(52=>53)
    Thread-5:Error:(52=>53)
    Thread-23:Error:(52=>53)
    Thread-15:Error:(52=>53)
    Thread-18:0:(52=>53)
    Thread-3:Error:(52=>53)
    Thread-30:0:(53=>54)
    Thread-22:Error:(53=>54)
    Thread-65:0:(54=>55)
    Thread-24:0:(55=>56)
    Thread-21:Error:(55=>56)
    Thread-32:Error:(55=>56)
    Thread-5:0:(56=>57)
    Thread-29:Error:(57=>58)
    Thread-15:0:(57=>58)
    Thread-23:Error:(57=>58)
    Thread-3:0:(58=>59)
    Thread-22:0:(59=>60)
    Thread-32:0:(60=>61)
    Thread-21:Error:(60=>61)
    Thread-29:0:(61=>62)
    Thread-23:Error:(61=>62)
    Thread-21:0:(62=>63)
    Thread-23:0:(63=>64)
    complete
    64
    复制代码

    备注:实际应用场景中我这里不是实现自增,上边代码自增目的:测试是否能够在高并发下修改同一个key时实现锁的功能。

    实际应用:高并发使用redis同一个key存储统计TOPN结果

    需求:

    1)拥有多个记录,每条记录数据格式:日期,统计指标1,统计指标2,统计指标3,统计指标4

    2)要求分别统计出4个指标的最大值,并记录各自指标最大值时对应的记录。

    3)记录中各个字段的模拟公式:

    复制代码
    // 数据格式:
    // 第一列:日期
    // 第二列:f(x) = x*0.7+1(x自然数)      最大值 45.1
    // 第三列:f(x)= -x*x+20x+1(自然数)    a=-1,b=20,c=1 , 当x=-b/2a时 y 最大值:-10*10+20*10+1=101
    // 第四列:f(x)= -x*x+30x+1(自然数)    a=-1,b=30,c=1 , 当x=-b/2a时 y 最大值:-15*15+30*15+1=445-225+1=221
    // 第五列:f(x)= 640/(x+1)(x自然数)    最大值 640    
    复制代码

    使用mutil+watch实现:

    首先,把最终统计结果存储到redis的key(lock_test)中,lock_test是一个hash类型,其中存储四个键值对,每个键值对分别存储各自的指标最大值时对应的记录。

    指标配置项存储到FeildConfig.java

    复制代码
        static class FieldConfig {
            private String key;
            private Integer index;
    
        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getKey() {
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> key;
        }
    
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setKey(String key) {
            </span><span style="color: #0000ff;">this</span>.key =<span style="color: #000000;"> key;
        }
    
        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Integer getIndex() {
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> index;
        }
    
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setIndex(Integer index) {
            </span><span style="color: #0000ff;">this</span>.index =<span style="color: #000000;"> index;
        }
    
        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> FieldConfig(String key, Integer index) {
            </span><span style="color: #0000ff;">super</span><span style="color: #000000;">();
            </span><span style="color: #0000ff;">this</span>.key =<span style="color: #000000;"> key;
            </span><span style="color: #0000ff;">this</span>.index =<span style="color: #000000;"> index;
        }
    }</span></pre>
    
    复制代码

    在测试类的static构造函数中初始化各自指标在一条记录的中索引位置,及一共包含的指标类型:

    复制代码
    public class Test_Lock3 {
        。。。
        final static List<FieldConfig> keys = new ArrayList<FieldConfig>();
    
    </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> {
        keys.add(</span><span style="color: #0000ff;">new</span> FieldConfig("101", 1<span style="color: #000000;">));
        keys.add(</span><span style="color: #0000ff;">new</span> FieldConfig("102", 2<span style="color: #000000;">));
        keys.add(</span><span style="color: #0000ff;">new</span> FieldConfig("103", 3<span style="color: #000000;">));
        keys.add(</span><span style="color: #0000ff;">new</span> FieldConfig("104", 4<span style="color: #000000;">));
    }
    。。。
    

    }

    复制代码

    备注:101代表指标1,对应在被统计记录中的第1索引位置(备注:这里索引是对记录按照“,”分割后的数组索引位置)。

    制作测试数据:

    复制代码
            List<String> dataItems=new ArrayList<String>();
    
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 数据格式:
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 第一列:日期
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 第二列:f(x) = x*0.7+1(x自然数)      最大值 45.1
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 第三列:f(x)= -x*x+20x+1(自然数)    a=-1,b=20,c=1 , 当x=-b/2a时 y 最大值:-10*10+20*10+1=101
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 第四列:f(x)= -x*x+30x+1(自然数)    a=-1,b=30,c=1 , 当x=-b/2a时 y 最大值:-15*15+30*15+1=445-225+1=221
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 第五列:f(x)= 640/(x+1)(x自然数)    最大值 640        </span>
        <span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> x=0;x&lt;threahSize;x++<span style="color: #000000;">){
            String dataItem </span>= "2018-07-29 00:00:00," + (x*0.7d+1) + "," + (-1d*x*x+20*x+1) + "," + (-1d*x*x+30*x+1) + "," + (640d/(x+1<span style="color: #000000;">));
            dataItems.add(dataItem);
        }</span></pre>
    
    复制代码

    以下是整体测试代码:

    复制代码
    package com.dx.es;
    

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.CountDownLatch;

    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.Transaction;

    public class Test_Lock3 {
    final static JedisPool pool = RedisUtil.getPool();
    final static List<FieldConfig> keys = new ArrayList<FieldConfig>();

    </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> {
        keys.add(</span><span style="color: #0000ff;">new</span> FieldConfig("101", 1<span style="color: #000000;">));
        keys.add(</span><span style="color: #0000ff;">new</span> FieldConfig("102", 2<span style="color: #000000;">));
        keys.add(</span><span style="color: #0000ff;">new</span> FieldConfig("103", 3<span style="color: #000000;">));
        keys.add(</span><span style="color: #0000ff;">new</span> FieldConfig("104", 4<span style="color: #000000;">));
    }
    
    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) {
        </span><span style="color: #0000ff;">int</span> threahSize = 64<span style="color: #000000;">;
        </span><span style="color: #0000ff;">final</span> CountDownLatch threadsCountDownLatch = <span style="color: #0000ff;">new</span><span style="color: #000000;"> CountDownLatch(threahSize);
        Jedis jedis </span>=<span style="color: #000000;"> pool.getResource();
        jedis.del(</span>"lock_test"<span style="color: #000000;">);
        
        List</span>&lt;String&gt; dataItems=<span style="color: #0000ff;">new</span> ArrayList&lt;String&gt;<span style="color: #000000;">();
    
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 数据格式:
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 第一列:日期
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 第二列:f(x) = x*0.7+1(x自然数)      最大值 45.1
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 第三列:f(x)= -x*x+20x+1(自然数)    a=-1,b=20,c=1 , 当x=-b/2a时 y 最大值:-10*10+20*10+1=101
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 第四列:f(x)= -x*x+30x+1(自然数)    a=-1,b=30,c=1 , 当x=-b/2a时 y 最大值:-15*15+30*15+1=445-225+1=221
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 第五列:f(x)= 640/(x+1)(x自然数)    最大值 640        </span>
        <span style="color: #0000ff;">for</span>(<span style="color: #0000ff;">int</span> x=0;x&lt;threahSize;x++<span style="color: #000000;">){
            String dataItem </span>= "2018-07-29 00:00:00," + (x*0.7d+1) + "," + (-1d*x*x+20*x+1) + "," + (-1d*x*x+30*x+1) + "," + (640d/(x+1<span style="color: #000000;">));
            dataItems.add(dataItem);
        }
        
        
        </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; threahSize; i++<span style="color: #000000;">) {
            Jedis jedisT </span>=<span style="color: #000000;"> pool.getResource();
            
            Runnable handler </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> MyRunable(jedisT, threadsCountDownLatch, dataItems.get(i));
    
            </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> Thread(handler).start();
        }
    
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> 等待所有并行子线程任务完成。</span>
        <span style="color: #0000ff;">try</span><span style="color: #000000;"> {
            threadsCountDownLatch.await();
        } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
            e.printStackTrace();
        }
    
        System.out.println(</span>"complete"<span style="color: #000000;">);
    
        Map</span>&lt;String, String&gt; values = jedis.hgetAll("lock_test"<span style="color: #000000;">);
        jedis.close();
    
        System.out.println(values);
    }
    
    </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">class</span> MyRunable <span style="color: #0000ff;">implements</span><span style="color: #000000;"> Runnable {
        </span><span style="color: #0000ff;">private</span> Jedis jedis = <span style="color: #0000ff;">null</span><span style="color: #000000;">;
        </span><span style="color: #0000ff;">private</span> CountDownLatch threadsCountDownLatch = <span style="color: #0000ff;">null</span><span style="color: #000000;">;
        </span><span style="color: #0000ff;">private</span> String newLine = <span style="color: #0000ff;">null</span><span style="color: #000000;">;
    
        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> MyRunable(Jedis jedis, CountDownLatch threadsCountDownLatch, String newLine) {
            </span><span style="color: #0000ff;">this</span>.jedis =<span style="color: #000000;"> jedis;
            </span><span style="color: #0000ff;">this</span>.threadsCountDownLatch =<span style="color: #000000;"> threadsCountDownLatch;
            </span><span style="color: #0000ff;">this</span>.newLine =<span style="color: #000000;"> newLine;
        }
    
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() {
            </span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">) {
                </span><span style="color: #0000ff;">this</span>.jedis.watch("lock_test"<span style="color: #000000;">);
    
                Map</span>&lt;String, String&gt; newValues = <span style="color: #0000ff;">new</span> HashMap&lt;String, String&gt;<span style="color: #000000;">();
                Map</span>&lt;String, String&gt; oldValues = <span style="color: #0000ff;">this</span>.jedis.hgetAll("lock_test"<span style="color: #000000;">);
                
                String newValueStr</span>=""<span style="color: #000000;">;
    
                </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (FieldConfig key : keys) {
                    </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (oldValues.containsKey(key.getKey())) {
                        Double oldValue </span>= Double.valueOf(oldValues.get(key.getKey()).split(","<span style="color: #000000;">)[key.getIndex()]);
                        Double newValue </span>= Double.valueOf(newLine.split(","<span style="color: #000000;">)[key.getIndex()]);
                        </span><span style="color: #0000ff;">if</span> (newValue &gt;<span style="color: #000000;"> oldValue) {
                            newValues.put(key.getKey(), newLine);
                            newValueStr</span>=<span style="color: #000000;">newLine;
                        } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
                            newValues.put(key.getKey(), oldValues.get(key.getKey()));
                            newValueStr</span>=<span style="color: #000000;">oldValues.get(key.getKey());
                        }
                    } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
                        newValues.put(key.getKey(), newLine);
                        newValueStr</span>=<span style="color: #000000;">newLine;
                    }
                }
    
                Transaction tx </span>= <span style="color: #0000ff;">this</span><span style="color: #000000;">.jedis.multi();
                tx.hmset(</span>"lock_test"<span style="color: #000000;">, newValues);
    
                List</span>&lt;Object&gt; exec =<span style="color: #000000;"> tx.exec();
    
                </span><span style="color: #0000ff;">if</span> (exec == <span style="color: #0000ff;">null</span> ||<span style="color: #000000;"> exec.isEmpty()) {
                    </span><span style="color: #008000;">//</span><span style="color: #008000;">System.out.println(Thread.currentThread().getName() + ":" + "Error:(" + oldValueStr + "-&gt;"+newValueStr+")");</span>
                } <span style="color: #0000ff;">else</span><span style="color: #000000;"> {
                    String values </span>= ""<span style="color: #000000;">;
                    </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i &lt; exec.size(); i++<span style="color: #000000;">) {
                        values </span>+=<span style="color: #000000;"> exec.get(i).toString();
                    }
                    System.out.println(Thread.currentThread().getName() </span>+ ":" + values + ":(" + newLine +"-&gt;"+newValueStr+")"<span style="color: #000000;">);
                    </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;
                }
    
                </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
                    Thread.sleep(</span>10<span style="color: #000000;">);
                } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.jedis.close();
            </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.threadsCountDownLatch.countDown();
        }
    }
    
    </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> FieldConfig {
        </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> String key;
        </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> Integer index;
    
        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getKey() {
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> key;
        }
    
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setKey(String key) {
            </span><span style="color: #0000ff;">this</span>.key =<span style="color: #000000;"> key;
        }
    
        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Integer getIndex() {
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> index;
        }
    
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setIndex(Integer index) {
            </span><span style="color: #0000ff;">this</span>.index =<span style="color: #000000;"> index;
        }
    
        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> FieldConfig(String key, Integer index) {
            </span><span style="color: #0000ff;">super</span><span style="color: #000000;">();
            </span><span style="color: #0000ff;">this</span>.key =<span style="color: #000000;"> key;
            </span><span style="color: #0000ff;">this</span>.index =<span style="color: #000000;"> index;
        }
    }
    

    }

    复制代码

    测试:

    复制代码
    Thread-23:OK:(2018-07-29 00:00:00,15.0,1.0,201.0,30.476190476190474->2018-07-29 00:00:00,15.0,1.0,201.0,30.476190476190474)
    Thread-29:OK:(2018-07-29 00:00:00,19.2,-155.0,105.0,23.703703703703702->2018-07-29 00:00:00,15.0,1.0,201.0,30.476190476190474)
    Thread-33:OK:(2018-07-29 00:00:00,22.0,-299.0,1.0,20.64516129032258->2018-07-29 00:00:00,15.0,1.0,201.0,30.476190476190474)
    Thread-24:OK:(2018-07-29 00:00:00,15.7,-20.0,190.0,29.09090909090909->2018-07-29 00:00:00,15.0,1.0,201.0,30.476190476190474)
    Thread-36:OK:(2018-07-29 00:00:00,24.099999999999998,-428.0,-98.0,18.823529411764707->2018-07-29 00:00:00,15.0,1.0,201.0,30.476190476190474)
    Thread-32:OK:(2018-07-29 00:00:00,21.299999999999997,-260.0,30.0,21.333333333333332->2018-07-29 00:00:00,15.0,1.0,201.0,30.476190476190474)
    Thread-39:OK:(2018-07-29 00:00:00,26.2,-575.0,-215.0,17.2972972972973->2018-07-29 00:00:00,15.0,1.0,201.0,30.476190476190474)
    Thread-40:OK:(2018-07-29 00:00:00,26.9,-628.0,-258.0,16.842105263157894->2018-07-29 00:00:00,15.0,1.0,201.0,30.476190476190474)
    Thread-25:OK:(2018-07-29 00:00:00,16.4,-43.0,177.0,27.82608695652174->2018-07-29 00:00:00,15.0,1.0,201.0,30.476190476190474)
    Thread-3:OK:(2018-07-29 00:00:00,1.0,1.0,1.0,640.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-16:OK:(2018-07-29 00:00:00,10.1,92.0,222.0,45.714285714285715->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-21:OK:(2018-07-29 00:00:00,13.6,37.0,217.0,33.68421052631579->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-45:OK:(2018-07-29 00:00:00,30.4,-923.0,-503.0,14.883720930232558->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-28:OK:(2018-07-29 00:00:00,18.5,-124.0,126.0,24.615384615384617->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-46:OK:(2018-07-29 00:00:00,31.099999999999998,-988.0,-558.0,14.545454545454545->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-12:OK:(2018-07-29 00:00:00,7.3,100.0,190.0,64.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-34:OK:(2018-07-29 00:00:00,22.7,-340.0,-30.0,20.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-49:OK:(2018-07-29 00:00:00,33.199999999999996,-1195.0,-735.0,13.617021276595745->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-50:OK:(2018-07-29 00:00:00,33.9,-1268.0,-798.0,13.333333333333334->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-52:OK:(2018-07-29 00:00:00,35.3,-1420.0,-930.0,12.8->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-53:OK:(2018-07-29 00:00:00,36.0,-1499.0,-999.0,12.549019607843137->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-54:OK:(2018-07-29 00:00:00,36.699999999999996,-1580.0,-1070.0,12.307692307692308->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-55:OK:(2018-07-29 00:00:00,37.4,-1663.0,-1143.0,12.075471698113208->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-56:OK:(2018-07-29 00:00:00,38.099999999999994,-1748.0,-1218.0,11.851851851851851->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-57:OK:(2018-07-29 00:00:00,38.8,-1835.0,-1295.0,11.636363636363637->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-58:OK:(2018-07-29 00:00:00,39.5,-1924.0,-1374.0,11.428571428571429->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-59:OK:(2018-07-29 00:00:00,40.199999999999996,-2015.0,-1455.0,11.228070175438596->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-60:OK:(2018-07-29 00:00:00,40.9,-2108.0,-1538.0,11.03448275862069->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-61:OK:(2018-07-29 00:00:00,41.599999999999994,-2203.0,-1623.0,10.847457627118644->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-62:OK:(2018-07-29 00:00:00,42.3,-2300.0,-1710.0,10.666666666666666->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-63:OK:(2018-07-29 00:00:00,43.0,-2399.0,-1799.0,10.491803278688524->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-64:OK:(2018-07-29 00:00:00,43.699999999999996,-2500.0,-1890.0,10.32258064516129->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-65:OK:(2018-07-29 00:00:00,44.4,-2603.0,-1983.0,10.158730158730158->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-11:OK:(2018-07-29 00:00:00,6.6,97.0,177.0,71.11111111111111->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-41:OK:(2018-07-29 00:00:00,27.599999999999998,-683.0,-303.0,16.41025641025641->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-47:OK:(2018-07-29 00:00:00,31.799999999999997,-1055.0,-615.0,14.222222222222221->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-37:OK:(2018-07-29 00:00:00,24.799999999999997,-475.0,-135.0,18.285714285714285->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-48:OK:(2018-07-29 00:00:00,32.5,-1124.0,-674.0,13.91304347826087->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-5:OK:(2018-07-29 00:00:00,2.4,37.0,57.0,213.33333333333334->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-42:OK:(2018-07-29 00:00:00,28.299999999999997,-740.0,-350.0,16.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-8:OK:(2018-07-29 00:00:00,4.5,76.0,126.0,106.66666666666667->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-9:OK:(2018-07-29 00:00:00,5.199999999999999,85.0,145.0,91.42857142857143->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-43:OK:(2018-07-29 00:00:00,29.0,-799.0,-399.0,15.609756097560975->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-7:OK:(2018-07-29 00:00:00,3.8,65.0,105.0,128.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-44:OK:(2018-07-29 00:00:00,29.7,-860.0,-450.0,15.238095238095237->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-18:OK:(2018-07-29 00:00:00,11.5,76.0,226.0,40.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-20:OK:(2018-07-29 00:00:00,12.899999999999999,52.0,222.0,35.55555555555556->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-15:OK:(2018-07-29 00:00:00,9.399999999999999,97.0,217.0,49.23076923076923->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-27:OK:(2018-07-29 00:00:00,17.799999999999997,-95.0,145.0,25.6->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-17:OK:(2018-07-29 00:00:00,10.799999999999999,85.0,225.0,42.666666666666664->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-10:OK:(2018-07-29 00:00:00,5.8999999999999995,92.0,162.0,80.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-66:OK:(2018-07-29 00:00:00,45.099999999999994,-2708.0,-2078.0,10.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-19:OK:(2018-07-29 00:00:00,12.2,65.0,225.0,37.64705882352941->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-26:OK:(2018-07-29 00:00:00,17.099999999999998,-68.0,162.0,26.666666666666668->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-4:OK:(2018-07-29 00:00:00,1.7,20.0,30.0,320.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-35:OK:(2018-07-29 00:00:00,23.4,-383.0,-63.0,19.393939393939394->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-22:OK:(2018-07-29 00:00:00,14.299999999999999,20.0,210.0,32.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-31:OK:(2018-07-29 00:00:00,20.599999999999998,-223.0,57.0,22.06896551724138->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-51:OK:(2018-07-29 00:00:00,34.599999999999994,-1343.0,-863.0,13.061224489795919->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-30:OK:(2018-07-29 00:00:00,19.9,-188.0,82.0,22.857142857142858->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-6:OK:(2018-07-29 00:00:00,3.0999999999999996,52.0,82.0,160.0->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-14:OK:(2018-07-29 00:00:00,8.7,100.0,210.0,53.333333333333336->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-13:OK:(2018-07-29 00:00:00,8.0,101.0,201.0,58.18181818181818->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    Thread-38:OK:(2018-07-29 00:00:00,25.5,-524.0,-174.0,17.77777777777778->2018-07-29 00:00:00,1.0,1.0,1.0,640.0)
    complete
    {
    101=2018-07-29 00:00:00,45.099999999999994,-2708.0,-2078.0,10.0,
    102
    =2018-07-29 00:00:00,8.0,101.0,201.0,58.18181818181818,
    103=2018-07-29 00:00:00,11.5,76.0,226.0,40.0,
    104=2018-07-29 00:00:00,1.0,1.0,1.0,640.0

    }
    复制代码

    参考:《通过Jedis的setnx、multi事务及watch实现三种分布式跨JVM锁的方法代码示例》注意:本章文章中介绍了三种锁的方案,但是这三种方案并不能解决topn的问题,仅供参考。



    感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文欢迎各位转载,但是转载文章之后必须在文章页面中给出作者和原文连接

    基础才是编程人员应该深入研究的问题,比如:
    1)List/Set/Map内部组成原理|区别
    2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
    3)JVM运行组成与原理及调优
    4)Java类加载器运行原理
    5)Java中GC过程原理|使用的回收算法原理
    6)Redis中hash一致性实现及与hash其他区别
    7)Java多线程、线程池开发、管理Lock与Synchroined区别
    8)Spring IOC/AOP 原理;加载过程的。。。
    +加关注】。

    分类: Redis
    标签: Redis
    0
    0
    « 上一篇:Redis:按照正则批量删除key
    » 下一篇:Spark参数设置的方式
    	</div>
    	<div class="postDesc">posted @ <span id="post-date">2018-07-29 13:33</span> <a href="https://www.cnblogs.com/yy3b2007com/">cctext</a> 阅读(<span id="post_view_count">4255</span>) 评论(<span id="post_comment_count">0</span>)  <a href="https://i.cnblogs.com/EditPosts.aspx?postid=9383713" rel="nofollow">编辑</a> <a href="#" onclick="AddToWz(9383713);return false;">收藏</a></div>
    </div>
  • 相关阅读:
    010-1 Socket地址族AddressFamily
    011 Socket定义客户端
    003 win7如何配置adb环境变量
    002 调试工具的具体功能
    001 Nibiru SDK 调试工具介绍
    001 UI介绍
    010 socket定义服务器
    001 Lua相关链接
    000 Lua目录
    深拷贝的、浅拷贝讲解以及示例
  • 原文地址:https://www.cnblogs.com/jpfss/p/10842664.html
Copyright © 2011-2022 走看看