Redis分布式锁----悲观锁实现,以秒杀系统为例

https://blog.csdn.net/evankaka/article/details/70568951


摘要:本文要实现的是一种使用redis来实现分布式锁。

本文源码请在这里下载:https://github.com/appleappleapple/DistributeLearning

1、分布式锁

    分布式锁在是一种用来安全访问分式式机器上变量的安全方案,一般用在全局id生成,秒杀系统,全局变量共享、分布式事务等。一般会有两种实现方案,一种是悲观锁的实现,一种是乐观锁的实现。悲观锁的并发性能差,但是能保证不会发生脏数据的可能性小一点。


2、Redis命令介绍
使用Redis实现分布式锁,有两个重要函数需要介绍

SETNX命令(SET if Not eXists)
语法:
SETNX key value
功能:
当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。

GETSET命令(这是一个原子命令!)
语法:
GETSET key value
功能:
将给定 key 的值设为 value ,并返回 key 的旧值 (old value),当 key 存在但不是字符串类型时,返回一个错误,当key不存在时,返回nil。

GET命令
语法:
GET key
功能:
返回 key 所关联的字符串值,如果 key 不存在那么返回特殊值 nil 。

DEL命令
语法:
DEL key [KEY …]
功能:
删除给定的一个或多个 key ,不存在的 key 会被忽略。

3、代码实现

(1)AbstractLock基类

[java]  view plain  copy
  1. package com.github.distribute.lock.redis;  
  2.   
  3. import java.util.concurrent.TimeUnit;  
  4. import java.util.concurrent.locks.Lock;  
  5.   
  6. /** 
  7.  * 锁的骨架实现, 真正的获取锁的步骤由子类去实现. 
  8.  *  
  9.  * 
  10.  */  
  11. public abstract class AbstractLock implements Lock {  
  12.   
  13.     /** 
  14.      * <pre> 
  15.      * 这里需不需要保证可见性值得讨论, 因为是分布式的锁,  
  16.      * 1.同一个jvm的多个线程使用不同的锁对象其实也是可以的, 这种情况下不需要保证可见性  
  17.      * 2.同一个jvm的多个线程使用同一个锁对象, 那可见性就必须要保证了. 
  18.      * </pre> 
  19.      */  
  20.     protected volatile boolean locked;  
  21.   
  22.     /** 
  23.      * 当前jvm内持有该锁的线程(if have one) 
  24.      */  
  25.     private Thread exclusiveOwnerThread;  
  26.   
  27.     public void lock() {  
  28.         try {  
  29.             lock(false0nullfalse);  
  30.         } catch (InterruptedException e) {  
  31.             // TODO ignore  
  32.         }  
  33.     }  
  34.   
  35.     public void lockInterruptibly() throws InterruptedException {  
  36.         lock(false0nulltrue);  
  37.     }  
  38.   
  39.     public boolean tryLock(long time, TimeUnit unit) {  
  40.         try {  
  41.             System.out.println("ghggggggggggggg");  
  42.             return lock(true, time, unit, false);  
  43.         } catch (InterruptedException e) {  
  44.             e.printStackTrace();  
  45.             System.out.println("" + e);  
  46.         }  
  47.         return false;  
  48.     }  
  49.   
  50.     public boolean tryLockInterruptibly(long time, TimeUnit unit) throws InterruptedException {  
  51.         return lock(true, time, unit, true);  
  52.     }  
  53.   
  54.     public void unlock() {  
  55.         // TODO 检查当前线程是否持有锁  
  56.         if (Thread.currentThread() != getExclusiveOwnerThread()) {  
  57.             throw new IllegalMonitorStateException("current thread does not hold the lock");  
  58.         }  
  59.   
  60.         unlock0();  
  61.         setExclusiveOwnerThread(null);  
  62.     }  
  63.   
  64.     protected void setExclusiveOwnerThread(Thread thread) {  
  65.         exclusiveOwnerThread = thread;  
  66.     }  
  67.   
  68.     protected final Thread getExclusiveOwnerThread() {  
  69.         return exclusiveOwnerThread;  
  70.     }  
  71.   
  72.     protected abstract void unlock0();  
  73.   
  74.     /** 
  75.      * 阻塞式获取锁的实现 
  76.      *  
  77.      * @param useTimeout 
  78.      * @param time 
  79.      * @param unit 
  80.      * @param interrupt 
  81.      *            是否响应中断 
  82.      * @return 
  83.      * @throws InterruptedException 
  84.      */  
  85.     protected abstract boolean lock(boolean useTimeout, long time, TimeUnit unit, boolean interrupt)  
  86.             throws InterruptedException;  
  87.   
  88. }  
(2)、实现类

[java]  view plain  copy
  1. package com.github.distribute.lock.redis;  
  2.   
  3. import java.util.concurrent.TimeUnit;  
  4. import java.util.concurrent.locks.Condition;  
  5.   
  6. import redis.clients.jedis.Jedis;  
  7.   
  8. /** 
  9.  * 基于Redis的SETNX操作实现的分布式锁 
  10.  *  
  11.  * 获取锁时最好用lock(long time, TimeUnit unit), 以免网路问题而导致线程一直阻塞 
  12.  */  
  13. public class RedisBasedDistributedLock extends AbstractLock {  
  14.   
  15.     private Jedis jedis;  
  16.   
  17.     // 锁的名字  
  18.     protected String lockKey;  
  19.   
  20.     // 锁的有效时长(毫秒)  
  21.     protected long lockExpires;  
  22.   
  23.     public RedisBasedDistributedLock(Jedis jedis, String lockKey, long lockExpires) {  
  24.         this.jedis = jedis;  
  25.         this.lockKey = lockKey;  
  26.         this.lockExpires = lockExpires;  
  27.     }  
  28.   
  29.     // 阻塞式获取锁的实现  
  30.     protected boolean lock(boolean useTimeout, long time, TimeUnit unit, boolean interrupt) throws InterruptedException {  
  31.         System.out.println("test1");  
  32.         if (interrupt) {  
  33.             checkInterruption();  
  34.         }  
  35.   
  36.         System.out.println("test2");  
  37.         long start = System.currentTimeMillis();  
  38.         long timeout = unit.toMillis(time); // if !useTimeout, then it's useless  
  39.   
  40.         while (useTimeout ? isTimeout(start, timeout) : true) {  
  41.             System.out.println("test3");  
  42.             if (interrupt) {  
  43.                 checkInterruption();  
  44.             }  
  45.   
  46.             long lockExpireTime = System.currentTimeMillis() + lockExpires + 1;// 锁超时时间  
  47.             String stringOfLockExpireTime = String.valueOf(lockExpireTime);  
  48.   
  49.             System.out.println("test4");  
  50.             if (jedis.setnx(lockKey, stringOfLockExpireTime) == 1) { // 获取到锁  
  51.                 System.out.println("test5");  
  52.                 //成功获取到锁, 设置相关标识  
  53.                 locked = true;  
  54.                 setExclusiveOwnerThread(Thread.currentThread());  
  55.                 return true;  
  56.             }  
  57.   
  58.             System.out.println("test6");  
  59.             String value = jedis.get(lockKey);  
  60.             if (value != null && isTimeExpired(value)) { // lock is expired  
  61.                 System.out.println("test7");  
  62.                 // 假设多个线程(非单jvm)同时走到这里  
  63.                 String oldValue = jedis.getSet(lockKey, stringOfLockExpireTime); //原子操作  
  64.                 // 但是走到这里时每个线程拿到的oldValue肯定不可能一样(因为getset是原子性的)  
  65.                 // 加入拿到的oldValue依然是expired的,那么就说明拿到锁了  
  66.                 System.out.println("test8");  
  67.                 if (oldValue != null && isTimeExpired(oldValue)) {  
  68.                     System.out.println("test9");  
  69.                     //成功获取到锁, 设置相关标识  
  70.                     locked = true;  
  71.                     setExclusiveOwnerThread(Thread.currentThread());  
  72.                     return true;  
  73.                 }  
  74.             } else {  
  75.                 // TODO lock is not expired, enter next loop retrying  
  76.             }  
  77.         }  
  78.         System.out.println("test10");  
  79.         return false;  
  80.     }  
  81.   
  82.     public boolean tryLock() {  
  83.         long lockExpireTime = System.currentTimeMillis() + lockExpires + 1;// 锁超时时间  
  84.         String stringOfLockExpireTime = String.valueOf(lockExpireTime);  
  85.   
  86.         if (jedis.setnx(lockKey, stringOfLockExpireTime) == 1) { // 获取到锁  
  87.             // 成功获取到锁, 设置相关标识  
  88.             locked = true;  
  89.             setExclusiveOwnerThread(Thread.currentThread());  
  90.             return true;  
  91.         }  
  92.   
  93.         String value = jedis.get(lockKey);  
  94.         if (value != null && isTimeExpired(value)) { // lock is expired  
  95.             // 假设多个线程(非单jvm)同时走到这里  
  96.             String oldValue = jedis.getSet(lockKey, stringOfLockExpireTime); //原子操作  
  97.             // 但是走到这里时每个线程拿到的oldValue肯定不可能一样(因为getset是原子性的)  
  98.             // 假如拿到的oldValue依然是expired的,那么就说明拿到锁了  
  99.             if (oldValue != null && isTimeExpired(oldValue)) {  
  100.                 //成功获取到锁, 设置相关标识  
  101.                 locked = true;  
  102.                 setExclusiveOwnerThread(Thread.currentThread());  
  103.                 return true;  
  104.             }  
  105.         } else {  
  106.             // TODO lock is not expired, enter next loop retrying  
  107.         }  
  108.   
  109.         return false;  
  110.     }  
  111.   
  112.     /** 
  113.      * Queries if this lock is held by any thread. 
  114.      *  
  115.      * @return {@code true} if any thread holds this lock and {@code false} 
  116.      *         otherwise 
  117.      */  
  118.     public boolean isLocked() {  
  119.         if (locked) {  
  120.             return true;  
  121.         } else {  
  122.             String value = jedis.get(lockKey);  
  123.             // TODO 这里其实是有问题的, 想:当get方法返回value后, 假设这个value已经是过期的了,  
  124.             // 而就在这瞬间, 另一个节点set了value, 这时锁是被别的线程(节点持有), 而接下来的判断  
  125.             // 是检测不出这种情况的.不过这个问题应该不会导致其它的问题出现, 因为这个方法的目的本来就  
  126.             // 不是同步控制, 它只是一种锁状态的报告.  
  127.             return !isTimeExpired(value);  
  128.         }  
  129.     }  
  130.   
  131.     @Override  
  132.     protected void unlock0() {  
  133.         // 判断锁是否过期  
  134.         String value = jedis.get(lockKey);  
  135.         if (!isTimeExpired(value)) {  
  136.             doUnlock();  
  137.         }  
  138.     }  
  139.   
  140.     private void checkInterruption() throws InterruptedException {  
  141.         if (Thread.currentThread().isInterrupted()) {  
  142.             throw new InterruptedException();  
  143.         }  
  144.     }  
  145.   
  146.     private boolean isTimeExpired(String value) {  
  147.         return Long.parseLong(value) < System.currentTimeMillis();  
  148.     }  
  149.   
  150.     private boolean isTimeout(long start, long timeout) {  
  151.         return start + timeout > System.currentTimeMillis();  
  152.     }  
  153.   
  154.     private void doUnlock() {  
  155.         jedis.del(lockKey);  
  156.     }  
  157.   
  158.     public Condition newCondition() {  
  159.         // TODO Auto-generated method stub  
  160.         return null;  
  161.     }  
  162.   
  163. }  
原理其实很简单,就是利用setNx和getSet这两个命令来实现。

SetNx如果返回为1,表示拿到锁,并设置超时失效时间。

getSet是一个原子操作,它是在锁超时后没释放会进入,这时有可能多个应用一同时进入,但是如果设置成功,会返回oldValue,如果两个oldvalue一样,表明拿到锁了


上面使用到的redis工具类

[java]  view plain  copy
  1. package com.github.distribute.lock.redis;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5. import java.util.Set;  
  6.   
  7. import org.slf4j.Logger;  
  8. import org.slf4j.LoggerFactory;  
  9.   
  10. import redis.clients.jedis.BinaryClient.LIST_POSITION;  
  11. import redis.clients.jedis.Jedis;  
  12. import redis.clients.jedis.JedisPool;  
  13. import redis.clients.jedis.JedisPoolConfig;  
  14.   
  15. public class RedisUtil {  
  16.   
  17.     private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtil.class);  
  18.   
  19.     private static JedisPool pool = null;  
  20.   
  21.     private static RedisUtil ru = new RedisUtil();  
  22.   
  23.     public static void main(String[] args) {  
  24.         RedisUtil redisUtil = RedisUtil.getInstance();  
  25.         redisUtil.set("test""test");  
  26.         LOGGER.info(redisUtil.get("test"));  
  27.     }  
  28.   
  29.     private RedisUtil() {  
  30.         if (pool == null) {  
  31.             String ip = "10.75.202.11";  
  32.             int port = 6379;  
  33.             JedisPoolConfig config = new JedisPoolConfig();  
  34.             // 控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;  
  35.             // 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。  
  36.             config.setMaxTotal(10000);  
  37.             // 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。  
  38.             config.setMaxIdle(2000);  
  39.             // 表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;  
  40.             config.setMaxWaitMillis(1000 * 100);  
  41.             config.setTestOnBorrow(true);  
  42.             pool = new JedisPool(config, ip, port, 100000);  
  43.         }  
  44.   
  45.     }  
  46.   
  47.     public Jedis getJedis() {  
  48.         Jedis jedis = pool.getResource();  
  49.         return jedis;  
  50.     }  
  51.   
  52.     public static RedisUtil getInstance() {  
  53.         return ru;  
  54.     }  
  55.   
  56.     /** 
  57.      * <p> 
  58.      * 通过key获取储存在redis中的value 
  59.      * </p> 
  60.      * <p> 
  61.      * 并释放连接 
  62.      * </p> 
  63.      *  
  64.      * @param key 
  65.      * @return 成功返回value 失败返回null 
  66.      */  
  67.     public String get(String key) {  
  68.         Jedis jedis = null;  
  69.         String value = null;  
  70.         try {  
  71.             jedis = pool.getResource();  
  72.             value = jedis.get(key);  
  73.         } catch (Exception e) {  
  74.             LOGGER.error(e.getMessage());  
  75.         } finally {  
  76.             returnResource(pool, jedis);  
  77.         }  
  78.         return value;  
  79.     }  
  80.   
  81.     /** 
  82.      * <p> 
  83.      * 向redis存入key和value,并释放连接资源 
  84.      * </p> 
  85.      * <p> 
  86.      * 如果key已经存在 则覆盖 
  87.      * </p> 
  88.      *  
  89.      * @param key 
  90.      * @param value 
  91.      * @return 成功 返回OK 失败返回 0 
  92.      */  
  93.     public String set(String key, String value) {  
  94.         Jedis jedis = null;  
  95.         try {  
  96.             jedis = pool.getResource();  
  97.             return jedis.set(key, value);  
  98.         } catch (Exception e) {  
  99.   
  100.             LOGGER.error(e.getMessage());  
  101.             return "0";  
  102.         } finally {  
  103.             returnResource(pool, jedis);  
  104.         }  
  105.     }  
  106.   
  107.     /** 
  108.      * <p> 
  109.      * 删除指定的key,也可以传入一个包含key的数组 
  110.      * </p> 
  111.      *  
  112.      * @param keys 
  113.      *            一个key 也可以使 string 数组 
  114.      * @return 返回删除成功的个数 
  115.      */  
  116.     public Long del(String... keys) {  
  117.         Jedis jedis = null;  
  118.         try {  
  119.             jedis = pool.getResource();  
  120.             return jedis.del(keys);  
  121.         } catch (Exception e) {  
  122.   
  123.             LOGGER.error(e.getMessage());  
  124.             return 0L;  
  125.         } finally {  
  126.             returnResource(pool, jedis);  
  127.         }  
  128.     }  
  129.   
  130.     /** 
  131.      * <p> 
  132.      * 通过key向指定的value值追加值 
  133.      * </p> 
  134.      *  
  135.      * @param key 
  136.      * @param str 
  137.      * @return 成功返回 添加后value的长度 失败 返回 添加的 value 的长度 异常返回0L 
  138.      */  
  139.     public Long append(String key, String str) {  
  140.         Jedis jedis = null;  
  141.         Long res = null;  
  142.         try {  
  143.             jedis = pool.getResource();  
  144.             res = jedis.append(key, str);  
  145.         } catch (Exception e) {  
  146.   
  147.             LOGGER.error(e.getMessage());  
  148.             return 0L;  
  149.         } finally {  
  150.             returnResource(pool, jedis);  
  151.         }  
  152.         return res;  
  153.     }  
  154.   
  155.     /** 
  156.      * <p> 
  157.      * 判断key是否存在 
  158.      * </p> 
  159.      *  
  160.      * @param key 
  161.      * @return true OR false 
  162.      */  
  163.     public Boolean exists(String key) {  
  164.         Jedis jedis = null;  
  165.         try {  
  166.             jedis = pool.getResource();  
  167.             return jedis.exists(key);  
  168.         } catch (Exception e) {  
  169.   
  170.             LOGGER.error(e.getMessage());  
  171.             return false;  
  172.         } finally {  
  173.             returnResource(pool, jedis);  
  174.         }  
  175.     }  
  176.   
  177.     /** 
  178.      * <p> 
  179.      * 设置key value,如果key已经存在则返回0,nx==> not exist 
  180.      * </p> 
  181.      *  
  182.      * @param key 
  183.      * @param value 
  184.      * @return 成功返回1 如果存在 和 发生异常 返回 0 
  185.      */  
  186.     public Long setnx(String key, String value) {  
  187.         Jedis jedis = null;  
  188.         try {  
  189.             jedis = pool.getResource();  
  190.             return jedis.setnx(key, value);  
  191.         } catch (Exception e) {  
  192.   
  193.             LOGGER.error(e.getMessage());  
  194.             return 0L;  
  195.         } finally {  
  196.             returnResource(pool, jedis);  
  197.         }  
  198.     }  
  199.   
  200.     /** 
  201.      * <p> 
  202.      * 设置key value并制定这个键值的有效期 
  203.      * </p> 
  204.      *  
  205.      * @param key 
  206.      * @param value 
  207.      * @param seconds 
  208.      *            单位:秒 
  209.      * @return 成功返回OK 失败和异常返回null 
  210.      */  
  211.     public String setex(String key, String value, int seconds) {  
  212.         Jedis jedis = null;  
  213.         String res = null;  
  214.         try {  
  215.             jedis = pool.getResource();  
  216.             res = jedis.setex(key, seconds, value);  
  217.         } catch (Exception e) {  
  218.   
  219.             LOGGER.error(e.getMessage());  
  220.         } finally {  
  221.             returnResource(pool, jedis);  
  222.         }  
  223.         return res;  
  224.     }  
  225.   
  226.     /** 
  227.      * <p> 
  228.      * 通过key 和offset 从指定的位置开始将原先value替换 
  229.      * </p> 
  230.      * <p> 
  231.      * 下标从0开始,offset表示从offset下标开始替换 
  232.      * </p> 
  233.      * <p> 
  234.      * 如果替换的字符串长度过小则会这样 
  235.      * </p> 
  236.      * <p> 
  237.      * example: 
  238.      * </p> 
  239.      * <p> 
  240.      * value : bigsea@zto.cn 
  241.      * </p> 
  242.      * <p> 
  243.      * str : abc 
  244.      * </p> 
  245.      * <P> 
  246.      * 从下标7开始替换 则结果为 
  247.      * </p> 
  248.      * <p> 
  249.      * RES : bigsea.abc.cn 
  250.      * </p> 
  251.      *  
  252.      * @param key 
  253.      * @param str 
  254.      * @param offset 
  255.      *            下标位置 
  256.      * @return 返回替换后 value 的长度 
  257.      */  
  258.     public Long setrange(String key, String str, int offset) {  
  259.         Jedis jedis = null;  
  260.         try {  
  261.             jedis = pool.getResource();  
  262.             return jedis.setrange(key, offset, str);  
  263.         } catch (Exception e) {  
  264.   
  265.             LOGGER.error(e.getMessage());  
  266.             return 0L;  
  267.         } finally {  
  268.             returnResource(pool, jedis);  
  269.         }  
  270.     }  
  271.   
  272.     /** 
  273.      * <p> 
  274.      * 通过批量的key获取批量的value 
  275.      * </p> 
  276.      *  
  277.      * @param keys 
  278.      *            string数组 也可以是一个key 
  279.      * @return 成功返回value的集合, 失败返回null的集合 ,异常返回空 
  280.      */  
  281.     public List<String> mget(String... keys) {  
  282.         Jedis jedis = null;  
  283.         List<String> values = null;  
  284.         try {  
  285.             jedis = pool.getResource();  
  286.             values = jedis.mget(keys);  
  287.         } catch (Exception e) {  
  288.   
  289.             LOGGER.error(e.getMessage());  
  290.         } finally {  
  291.             returnResource(pool, jedis);  
  292.         }  
  293.         return values;  
  294.     }  
  295.   
  296.     /** 
  297.      * <p> 
  298.      * 批量的设置key:value,可以一个 
  299.      * </p> 
  300.      * <p> 
  301.      * example: 
  302.      * </p> 
  303.      * <p> 
  304.      * obj.mset(new String[]{"key2","value1","key2","value2"}) 
  305.      * </p> 
  306.      *  
  307.      * @param keysvalues 
  308.      * @return 成功返回OK 失败 异常 返回 null 
  309.      * 
  310.      */  
  311.     public String mset(String... keysvalues) {  
  312.         Jedis jedis = null;  
  313.         String res = null;  
  314.         try {  
  315.             jedis = pool.getResource();  
  316.             res = jedis.mset(keysvalues);  
  317.         } catch (Exception e) {  
  318.   
  319.             LOGGER.error(e.getMessage());  
  320.         } finally {  
  321.             returnResource(pool, jedis);  
  322.         }  
  323.         return res;  
  324.     }  
  325.   
  326.     /** 
  327.      * <p> 
  328.      * 批量的设置key:value,可以一个,如果key已经存在则会失败,操作会回滚 
  329.      * </p> 
  330.      * <p> 
  331.      * example: 
  332.      * </p> 
  333.      * <p> 
  334.      * obj.msetnx(new String[]{"key2","value1","key2","value2"}) 
  335.      * </p> 
  336.      *  
  337.      * @param keysvalues 
  338.      * @return 成功返回1 失败返回0 
  339.      */  
  340.     public Long msetnx(String... keysvalues) {  
  341.         Jedis jedis = null;  
  342.         Long res = 0L;  
  343.         try {  
  344.             jedis = pool.getResource();  
  345.             res = jedis.msetnx(keysvalues);  
  346.         } catch (Exception e) {  
  347.   
  348.             LOGGER.error(e.getMessage());  
  349.         } finally {  
  350.             returnResource(pool, jedis);  
  351.         }  
  352.         return res;  
  353.     }  
  354.   
  355.     /** 
  356.      * <p> 
  357.      * 设置key的值,并返回一个旧值 
  358.      * </p> 
  359.      *  
  360.      * @param key 
  361.      * @param value 
  362.      * @return 旧值 如果key不存在 则返回null 
  363.      */  
  364.     public String getset(String key, String value) {  
  365.         Jedis jedis = null;  
  366.         String res = null;  
  367.         try {  
  368.             jedis = pool.getResource();  
  369.             res = jedis.getSet(key, value);  
  370.         } catch (Exception e) {  
  371.   
  372.             LOGGER.error(e.getMessage());  
  373.         } finally {  
  374.             returnResource(pool, jedis);  
  375.         }  
  376.         return res;  
  377.     }  
  378.   
  379.     /** 
  380.      * <p> 
  381.      * 通过下标 和key 获取指定下标位置的 value 
  382.      * </p> 
  383.      *  
  384.      * @param key 
  385.      * @param startOffset 
  386.      *            开始位置 从0 开始 负数表示从右边开始截取 
  387.      * @param endOffset 
  388.      * @return 如果没有返回null 
  389.      */  
  390.     public String getrange(String key, int startOffset, int endOffset) {  
  391.         Jedis jedis = null;  
  392.         String res = null;  
  393.         try {  
  394.             jedis = pool.getResource();  
  395.             res = jedis.getrange(key, startOffset, endOffset);  
  396.         } catch (Exception e) {  
  397.   
  398.             LOGGER.error(e.getMessage());  
  399.         } finally {  
  400.             returnResource(pool, jedis);  
  401.         }  
  402.         return res;  
  403.     }  
  404.   
  405.     /** 
  406.      * <p> 
  407.      * 通过key 对value进行加值+1操作,当value不是int类型时会返回错误,当key不存在是则value为1 
  408.      * </p> 
  409.      *  
  410.      * @param key 
  411.      * @return 加值后的结果 
  412.      */  
  413.     public Long incr(String key) {  
  414.         Jedis jedis = null;  
  415.         Long res = null;  
  416.         try {  
  417.             jedis = pool.getResource();  
  418.             res = jedis.incr(key);  
  419.         } catch (Exception e) {  
  420.   
  421.             LOGGER.error(e.getMessage());  
  422.         } finally {  
  423.             returnResource(pool, jedis);  
  424.         }  
  425.         return res;  
  426.     }  
  427.   
  428.     /** 
  429.      * <p> 
  430.      * 通过key给指定的value加值,如果key不存在,则这是value为该值 
  431.      * </p> 
  432.      *  
  433.      * @param key 
  434.      * @param integer 
  435.      * @return 
  436.      */  
  437.     public Long incrBy(String key, Long integer) {  
  438.         Jedis jedis = null;  
  439.         Long res = null;  
  440.         try {  
  441.             jedis = pool.getResource();  
  442.             res = jedis.incrBy(key, integer);  
  443.         } catch (Exception e) {  
  444.   
  445.             LOGGER.error(e.getMessage());  
  446.         } finally {  
  447.             returnResource(pool, jedis);  
  448.         }  
  449.         return res;  
  450.     }  
  451.   
  452.     /** 
  453.      * <p> 
  454.      * 对key的值做减减操作,如果key不存在,则设置key为-1 
  455.      * </p> 
  456.      *  
  457.      * @param key 
  458.      * @return 
  459.      */  
  460.     public Long decr(String key) {  
  461.         Jedis jedis = null;  
  462.         Long res = null;  
  463.         try {  
  464.             jedis = pool.getResource();  
  465.             res = jedis.decr(key);  
  466.         } catch (Exception e) {  
  467.   
  468.             LOGGER.error(e.getMessage());  
  469.         } finally {  
  470.             returnResource(pool, jedis);  
  471.         }  
  472.         return res;  
  473.     }  
  474.   
  475.     /** 
  476.      * <p> 
  477.      * 减去指定的值 
  478.      * </p> 
  479.      *  
  480.      * @param key 
  481.      * @param integer 
  482.      * @return 
  483.      */  
  484.     public Long decrBy(String key, Long integer) {  
  485.         Jedis jedis = null;  
  486.         Long res = null;  
  487.         try {  
  488.             jedis = pool.getResource();  
  489.             res = jedis.decrBy(key, integer);  
  490.         } catch (Exception e) {  
  491.   
  492.             LOGGER.error(e.getMessage());  
  493.         } finally {  
  494.             returnResource(pool, jedis);  
  495.         }  
  496.         return res;  
  497.     }  
  498.   
  499.     /** 
  500.      * <p> 
  501.      * 通过key获取value值的长度 
  502.      * </p> 
  503.      *  
  504.      * @param key 
  505.      * @return 失败返回null 
  506.      */  
  507.     public Long serlen(String key) {  
  508.         Jedis jedis = null;  
  509.         Long res = null;  
  510.         try {  
  511.             jedis = pool.getResource();  
  512.             res = jedis.strlen(key);  
  513.         } catch (Exception e) {  
  514.   
  515.             LOGGER.error(e.getMessage());  
  516.         } finally {  
  517.             returnResource(pool, jedis);  
  518.         }  
  519.         return res;  
  520.     }  
  521.   
  522.     /** 
  523.      * <p> 
  524.      * 通过key给field设置指定的值,如果key不存在,则先创建 
  525.      * </p> 
  526.      *  
  527.      * @param key 
  528.      * @param field 
  529.      *            字段 
  530.      * @param value 
  531.      * @return 如果存在返回0 异常返回null 
  532.      */  
  533.     public Long hset(String key, String field, String value) {  
  534.         Jedis jedis = null;  
  535.         Long res = null;  
  536.         try {  
  537.             jedis = pool.getResource();  
  538.             res = jedis.hset(key, field, value);  
  539.         } catch (Exception e) {  
  540.   
  541.             LOGGER.error(e.getMessage());  
  542.         } finally {  
  543.             returnResource(pool, jedis);  
  544.         }  
  545.         return res;  
  546.     }  
  547.   
  548.     /** 
  549.      * <p> 
  550.      * 通过key给field设置指定的值,如果key不存在则先创建,如果field已经存在,返回0 
  551.      * </p> 
  552.      *  
  553.      * @param key 
  554.      * @param field 
  555.      * @param value 
  556.      * @return 
  557.      */  
  558.     public Long hsetnx(String key, String field, String value) {  
  559.         Jedis jedis = null;  
  560.         Long res = null;  
  561.         try {  
  562.             jedis = pool.getResource();  
  563.             res = jedis.hsetnx(key, field, value);  
  564.         } catch (Exception e) {  
  565.   
  566.             LOGGER.error(e.getMessage());  
  567.         } finally {  
  568.             returnResource(pool, jedis);  
  569.         }  
  570.         return res;  
  571.     }  
  572.   
  573.     /** 
  574.      * <p> 
  575.      * 通过key同时设置 hash的多个field 
  576.      * </p> 
  577.      *  
  578.      * @param key 
  579.      * @param hash 
  580.      * @return 返回OK 异常返回null 
  581.      */  
  582.     public String hmset(String key, Map<String, String> hash) {  
  583.         Jedis jedis = null;  
  584.         String res = null;  
  585.         try {  
  586.             jedis = pool.getResource();  
  587.             res = jedis.hmset(key, hash);  
  588.         } catch (Exception e) {  
  589.   
  590.             LOGGER.error(e.getMessage());  
  591.         } finally {  
  592.             returnResource(pool, jedis);  
  593.         }  
  594.         return res;  
  595.     }  
  596.   
  597.     /** 
  598.      * <p> 
  599.      * 通过key 和 field 获取指定的 value 
  600.      * </p> 
  601.      *  
  602.      * @param key 
  603.      * @param field 
  604.      * @return 没有返回null 
  605.      */  
  606.     public String hget(String key, String field) {  
  607.         Jedis jedis = null;  
  608.         String res = null;  
  609.         try {  
  610.             jedis = pool.getResource();  
  611.             res = jedis.hget(key, field);  
  612.         } catch (Exception e) {  
  613.   
  614.             LOGGER.error(e.getMessage());  
  615.         } finally {  
  616.             returnResource(pool, jedis);  
  617.         }  
  618.         return res;  
  619.     }  
  620.   
  621.     /** 
  622.      * <p> 
  623.      * 通过key 和 fields 获取指定的value 如果没有对应的value则返回null 
  624.      * </p> 
  625.      *  
  626.      * @param key 
  627.      * @param fields 
  628.      *            可以使 一个String 也可以是 String数组 
  629.      * @return 
  630.      */  
  631.     public List<String> hmget(String key, String... fields) {  
  632.         Jedis jedis = null;  
  633.         List<String> res = null;  
  634.         try {  
  635.             jedis = pool.getResource();  
  636.             res = jedis.hmget(key, fields);  
  637.         } catch (Exception e) {  
  638.   
  639.             LOGGER.error(e.getMessage());  
  640.         } finally {  
  641.             returnResource(pool, jedis);  
  642.         }  
  643.         return res;  
  644.     }  
  645.   
  646.     /** 
  647.      * <p> 
  648.      * 通过key给指定的field的value加上给定的值 
  649.      * </p> 
  650.      *  
  651.      * @param key 
  652.      * @param field 
  653.      * @param value 
  654.      * @return 
  655.      */  
  656.     public Long hincrby(String key, String field, Long value) {  
  657.         Jedis jedis = null;  
  658.         Long res = null;  
  659.         try {  
  660.             jedis = pool.getResource();  
  661.             res = jedis.hincrBy(key, field, value);  
  662.         } catch (Exception e) {  
  663.   
  664.             LOGGER.error(e.getMessage());  
  665.         } finally {  
  666.             returnResource(pool, jedis);  
  667.         }  
  668.         return res;  
  669.     }  
  670.   
  671.     /** 
  672.      * <p> 
  673.      * 通过key和field判断是否有指定的value存在 
  674.      * </p> 
  675.      *  
  676.      * @param key 
  677.      * @param field 
  678.      * @return 
  679.      */  
  680.     public Boolean hexists(String key, String field) {  
  681.         Jedis jedis = null;  
  682.         Boolean res = false;  
  683.         try {  
  684.             jedis = pool.getResource();  
  685.             res = jedis.hexists(key, field);  
  686.         } catch (Exception e) {  
  687.   
  688.             LOGGER.error(e.getMessage());  
  689.         } finally {  
  690.             returnResource(pool, jedis);  
  691.         }  
  692.         return res;  
  693.     }  
  694.   
  695.     /** 
  696.      * <p> 
  697.      * 通过key返回field的数量 
  698.      * </p> 
  699.      *  
  700.      * @param key 
  701.      * @return 
  702.      */  
  703.     public Long hlen(String key) {  
  704.         Jedis jedis = null;  
  705.         Long res = null;  
  706.         try {  
  707.             jedis = pool.getResource();  
  708.             res = jedis.hlen(key);  
  709.         } catch (Exception e) {  
  710.   
  711.             LOGGER.error(e.getMessage());  
  712.         } finally {  
  713.             returnResource(pool, jedis);  
  714.         }  
  715.         return res;  
  716.   
  717.     }  
  718.   
  719.     /** 
  720.      * <p> 
  721.      * 通过key 删除指定的 field 
  722.      * </p> 
  723.      *  
  724.      * @param key 
  725.      * @param fields 
  726.      *            可以是 一个 field 也可以是 一个数组 
  727.      * @return 
  728.      */  
  729.     public Long hdel(String key, String... fields) {  
  730.         Jedis jedis = null;  
  731.         Long res = null;  
  732.         try {  
  733.             jedis = pool.getResource();  
  734.             res = jedis.hdel(key, fields);  
  735.         } catch (Exception e) {  
  736.   
  737.             LOGGER.error(e.getMessage());  
  738.         } finally {  
  739.             returnResource(pool, jedis);  
  740.         }  
  741.         return res;  
  742.     }  
  743.   
  744.     /** 
  745.      * <p> 
  746.      * 通过key返回所有的field 
  747.      * </p> 
  748.      *  
  749.      * @param key 
  750.      * @return 
  751.      */  
  752.     public Set<String> hkeys(String key) {  
  753.         Jedis jedis = null;  
  754.         Set<String> res = null;  
  755.         try {  
  756.             jedis = pool.getResource();  
  757.             res = jedis.hkeys(key);  
  758.         } catch (Exception e) {  
  759.   
  760.             LOGGER.error(e.getMessage());  
  761.         } finally {  
  762.             returnResource(pool, jedis);  
  763.         }  
  764.         return res;  
  765.     }  
  766.   
  767.     /** 
  768.      * <p> 
  769.      * 通过key返回所有和key有关的value 
  770.      * </p> 
  771.      *  
  772.      * @param key 
  773.      * @return 
  774.      */  
  775.     public List<String> hvals(String key) {  
  776.         Jedis jedis = null;  
  777.         List<String> res = null;  
  778.         try {  
  779.             jedis = pool.getResource();  
  780.             res = jedis.hvals(key);  
  781.         } catch (Exception e) {  
  782.   
  783.             LOGGER.error(e.getMessage());  
  784.         } finally {  
  785.             returnResource(pool, jedis);  
  786.         }  
  787.         return res;  
  788.     }  
  789.   
  790.     /** 
  791.      * <p> 
  792.      * 通过key获取所有的field和value 
  793.      * </p> 
  794.      *  
  795.      * @param key 
  796.      * @return 
  797.      */  
  798.     public Map<String, String> hgetall(String key) {  
  799.         Jedis jedis = null;  
  800.         Map<String, String> res = null;  
  801.         try {  
  802.             jedis = pool.getResource();  
  803.             res = jedis.hgetAll(key);  
  804.         } catch (Exception e) {  
  805.             // TODO  
  806.         } finally {  
  807.             returnResource(pool, jedis);  
  808.         }  
  809.         return res;  
  810.     }  
  811.   
  812.     /** 
  813.      * <p> 
  814.      * 通过key向list头部添加字符串 
  815.      * </p> 
  816.      *  
  817.      * @param key 
  818.      * @param strs 
  819.      *            可以使一个string 也可以使string数组 
  820.      * @return 返回list的value个数 
  821.      */  
  822.     public Long lpush(String key, String... strs) {  
  823.         Jedis jedis = null;  
  824.         Long res = null;  
  825.         try {  
  826.             jedis = pool.getResource();  
  827.             res = jedis.lpush(key, strs);  
  828.         } catch (Exception e) {  
  829.   
  830.             LOGGER.error(e.getMessage());  
  831.         } finally {  
  832.             returnResource(pool, jedis);  
  833.         }  
  834.         return res;  
  835.     }  
  836.   
  837.     /** 
  838.      * <p> 
  839.      * 通过key向list尾部添加字符串 
  840.      * </p> 
  841.      *  
  842.      * @param key 
  843.      * @param strs 
  844.      *            可以使一个string 也可以使string数组 
  845.      * @return 返回list的value个数 
  846.      */  
  847.     public Long rpush(String key, String... strs) {  
  848.         Jedis jedis = null;  
  849.         Long res = null;  
  850.         try {  
  851.             jedis = pool.getResource();  
  852.             res = jedis.rpush(key, strs);  
  853.         } catch (Exception e) {  
  854.   
  855.             LOGGER.error(e.getMessage());  
  856.         } finally {  
  857.             returnResource(pool, jedis);  
  858.         }  
  859.         return res;  
  860.     }  
  861.   
  862.     /** 
  863.      * <p> 
  864.      * 通过key在list指定的位置之前或者之后 添加字符串元素 
  865.      * </p> 
  866.      *  
  867.      * @param key 
  868.      * @param where 
  869.      *            LIST_POSITION枚举类型 
  870.      * @param pivot 
  871.      *            list里面的value 
  872.      * @param value 
  873.      *            添加的value 
  874.      * @return 
  875.      */  
  876.     public Long linsert(String key, LIST_POSITION where, String pivot, String value) {  
  877.         Jedis jedis = null;  
  878.         Long res = null;  
  879.         try {  
  880.             jedis = pool.getResource();  
  881.             res = jedis.linsert(key, where, pivot, value);  
  882.         } catch (Exception e) {  
  883.   
  884.             LOGGER.error(e.getMessage());  
  885.         } finally {  
  886.             returnResource(pool, jedis);  
  887.         }  
  888.         return res;  
  889.     }  
  890.   
  891.     /** 
  892.      * <p> 
  893.      * 通过key设置list指定下标位置的value 
  894.      * </p> 
  895.      * <p> 
  896.      * 如果下标超过list里面value的个数则报错 
  897.      * </p> 
  898.      *  
  899.      * @param key 
  900.      * @param index 
  901.      *            从0开始 
  902.      * @param value 
  903.      * @return 成功返回OK 
  904.      */  
  905.     public String lset(String key, Long index, String value) {  
  906.         Jedis jedis = null;  
  907.         String res = null;  
  908.         try {  
  909.             jedis = pool.getResource();  
  910.             res = jedis.lset(key, index, value);  
  911.         } catch (Exception e) {  
  912.   
  913.             LOGGER.error(e.getMessage());  
  914.         } finally {  
  915.             returnResource(pool, jedis);  
  916.         }  
  917.         return res;  
  918.     }  
  919.   
  920.     /** 
  921.      * <p> 
  922.      * 通过key从对应的list中删除指定的count个 和 value相同的元素 
  923.      * </p> 
  924.      *  
  925.      * @param key 
  926.      * @param count 
  927.      *            当count为0时删除全部 
  928.      * @param value 
  929.      * @return 返回被删除的个数 
  930.      */  
  931.     public Long lrem(String key, long count, String value) {  
  932.         Jedis jedis = null;  
  933.         Long res = null;  
  934.         try {  
  935.             jedis = pool.getResource();  
  936.             res = jedis.lrem(key, count, value);  
  937.         } catch (Exception e) {  
  938.   
  939.             LOGGER.error(e.getMessage());  
  940.         } finally {  
  941.             returnResource(pool, jedis);  
  942.         }  
  943.         return res;  
  944.     }  
  945.   
  946.     /** 
  947.      * <p> 
  948.      * 通过key保留list中从strat下标开始到end下标结束的value值 
  949.      * </p> 
  950.      *  
  951.      * @param key 
  952.      * @param start 
  953.      * @param end 
  954.      * @return 成功返回OK 
  955.      */  
  956.     public String ltrim(String key, long start, long end) {  
  957.         Jedis jedis = null;  
  958.         String res = null;  
  959.         try {  
  960.             jedis = pool.getResource();  
  961.             res = jedis.ltrim(key, start, end);  
  962.         } catch (Exception e) {  
  963.   
  964.             LOGGER.error(e.getMessage());  
  965.         } finally {  
  966.             returnResource(pool, jedis);  
  967.         }  
  968.         return res;  
  969.     }  
  970.   
  971.     /** 
  972.      * <p> 
  973.      * 通过key从list的头部删除一个value,并返回该value 
  974.      * </p> 
  975.      *  
  976.      * @param key 
  977.      * @return 
  978.      */  
  979.     synchronized public String lpop(String key) {  
  980.         Jedis jedis = null;  
  981.         String res = null;  
  982.         try {  
  983.             jedis = pool.getResource();  
  984.             res = jedis.lpop(key);  
  985.         } catch (Exception e) {  
  986.   
  987.             LOGGER.error(e.getMessage());  
  988.         } finally {  
  989.             returnResource(pool, jedis);  
  990.         }  
  991.         return res;  
  992.     }  
  993.   
  994.     /** 
  995.      * <p> 
  996.      * 通过key从list尾部删除一个value,并返回该元素 
  997.      * </p> 
  998.      *  
  999.      * @param key 
  1000.      * @return 
  1001.      */  
  1002.     synchronized public String rpop(String key) {  
  1003.         Jedis jedis = null;  
  1004.         String res = null;  
  1005.         try {  
  1006.             jedis = pool.getResource();  
  1007.             res = jedis.rpop(key);  
  1008.         } catch (Exception e) {  
  1009.   
  1010.             LOGGER.error(e.getMessage());  
  1011.         } finally {  
  1012.             returnResource(pool, jedis);  
  1013.         }  
  1014.         return res;  
  1015.     }  
  1016.   
  1017.     /** 
  1018.      * <p> 
  1019.      * 通过key从一个list的尾部删除一个value并添加到另一个list的头部,并返回该value 
  1020.      * </p> 
  1021.      * <p> 
  1022.      * 如果第一个list为空或者不存在则返回null 
  1023.      * </p> 
  1024.      *  
  1025.      * @param srckey 
  1026.      * @param dstkey 
  1027.      * @return 
  1028.      */  
  1029.     public String rpoplpush(String srckey, String dstkey) {  
  1030.         Jedis jedis = null;  
  1031.         String res = null;  
  1032.         try {  
  1033.             jedis = pool.getResource();  
  1034.             res = jedis.rpoplpush(srckey, dstkey);  
  1035.         } catch (Exception e) {  
  1036.   
  1037.             LOGGER.error(e.getMessage());  
  1038.         } finally {  
  1039.             returnResource(pool, jedis);  
  1040.         }  
  1041.         return res;  
  1042.     }  
  1043.   
  1044.     /** 
  1045.      * <p> 
  1046.      * 通过key获取list中指定下标位置的value 
  1047.      * </p> 
  1048.      *  
  1049.      * @param key 
  1050.      * @param index 
  1051.      * @return 如果没有返回null 
  1052.      */  
  1053.     public String lindex(String key, long index) {  
  1054.         Jedis jedis = null;  
  1055.         String res = null;  
  1056.         try {  
  1057.             jedis = pool.getResource();  
  1058.             res = jedis.lindex(key, index);  
  1059.         } catch (Exception e) {  
  1060.   
  1061.             LOGGER.error(e.getMessage());  
  1062.         } finally {  
  1063.             returnResource(pool, jedis);  
  1064.         }  
  1065.         return res;  
  1066.     }  
  1067.   
  1068.     /** 
  1069.      * <p> 
  1070.      * 通过key返回list的长度 
  1071.      * </p> 
  1072.      *  
  1073.      * @param key 
  1074.      * @return 
  1075.      */  
  1076.     public Long llen(String key) {  
  1077.         Jedis jedis = null;  
  1078.         Long res = null;  
  1079.         try {  
  1080.             jedis = pool.getResource();  
  1081.             res = jedis.llen(key);  
  1082.         } catch (Exception e) {  
  1083.   
  1084.             LOGGER.error(e.getMessage());  
  1085.         } finally {  
  1086.             returnResource(pool, jedis);  
  1087.         }  
  1088.         return res;  
  1089.     }  
  1090.   
  1091.     /** 
  1092.      * <p> 
  1093.      * 通过key获取list指定下标位置的value 
  1094.      * </p> 
  1095.      * <p> 
  1096.      * 如果start 为 0 end 为 -1 则返回全部的list中的value 
  1097.      * </p> 
  1098.      *  
  1099.      * @param key 
  1100.      * @param start 
  1101.      * @param end 
  1102.      * @return 
  1103.      */  
  1104.     public List<String> lrange(String key, long start, long end) {  
  1105.         Jedis jedis = null;  
  1106.         List<String> res = null;  
  1107.         try {  
  1108.             jedis = pool.getResource();  
  1109.             res = jedis.lrange(key, start, end);  
  1110.         } catch (Exception e) {  
  1111.   
  1112.             LOGGER.error(e.getMessage());  
  1113.         } finally {  
  1114.             returnResource(pool, jedis);  
  1115.         }  
  1116.         return res;  
  1117.     }  
  1118.   
  1119.     /** 
  1120.      * <p> 
  1121.      * 通过key向指定的set中添加value 
  1122.      * </p> 
  1123.      *  
  1124.      * @param key 
  1125.      * @param members 
  1126.      *            可以是一个String 也可以是一个String数组 
  1127.      * @return 添加成功的个数 
  1128.      */  
  1129.     public Long sadd(String key, String... members) {  
  1130.         Jedis jedis = null;  
  1131.         Long res = null;  
  1132.         try {  
  1133.             jedis = pool.getResource();  
  1134.             res = jedis.sadd(key, members);  
  1135.         } catch (Exception e) {  
  1136.   
  1137.             LOGGER.error(e.getMessage());  
  1138.         } finally {  
  1139.             returnResource(pool, jedis);  
  1140.         }  
  1141.         return res;  
  1142.     }  
  1143.   
  1144.     /** 
  1145.      * <p> 
  1146.      * 通过key删除set中对应的value值 
  1147.      * </p> 
  1148.      *  
  1149.      * @param key 
  1150.      * @param members 
  1151.      *            可以是一个String 也可以是一个String数组 
  1152.      * @return 删除的个数 
  1153.      */  
  1154.     public Long srem(String key, String... members) {  
  1155.         Jedis jedis = null;  
  1156.         Long res = null;  
  1157.         try {  
  1158.             jedis = pool.getResource();  
  1159.             res = jedis.srem(key, members);  
  1160.         } catch (Exception e) {  
  1161.   
  1162.             LOGGER.error(e.getMessage());  
  1163.         } finally {  
  1164.             returnResource(pool, jedis);  
  1165.         }  
  1166.         return res;  
  1167.     }  
  1168.   
  1169.     /** 
  1170.      * <p> 
  1171.      * 通过key随机删除一个set中的value并返回该值 
  1172.      * </p> 
  1173.      *  
  1174.      * @param key 
  1175.      * @return 
  1176.      */  
  1177.     public String spop(String key) {  
  1178.         Jedis jedis = null;  
  1179.         String res = null;  
  1180.         try {  
  1181.             jedis = pool.getResource();  
  1182.             res = jedis.spop(key);  
  1183.         } catch (Exception e) {  
  1184.   
  1185.             LOGGER.error(e.getMessage());  
  1186.         } finally {  
  1187.             returnResource(pool, jedis);  
  1188.         }  
  1189.         return res;  
  1190.     }  
  1191.   
  1192.     /** 
  1193.      * <p> 
  1194.      * 通过key获取set中的差集 
  1195.      * </p> 
  1196.      * <p> 
  1197.      * 以第一个set为标准 
  1198.      * </p> 
  1199.      *  
  1200.      * @param keys 
  1201.      *            可以使一个string 则返回set中所有的value 也可以是string数组 
  1202.      * @return 
  1203.      */  
  1204.     public Set<String> sdiff(String... keys) {  
  1205.         Jedis jedis = null;  
  1206.         Set<String> res = null;  
  1207.         try {  
  1208.             jedis = pool.getResource();  
  1209.             res = jedis.sdiff(keys);  
  1210.         } catch (Exception e) {  
  1211.   
  1212.             LOGGER.error(e.getMessage());  
  1213.         } finally {  
  1214.             returnResource(pool, jedis);  
  1215.         }  
  1216.         return res;  
  1217.     }  
  1218.   
  1219.     /** 
  1220.      * <p> 
  1221.      * 通过key获取set中的差集并存入到另一个key中 
  1222.      * </p> 
  1223.      * <p> 
  1224.      * 以第一个set为标准 
  1225.      * </p> 
  1226.      *  
  1227.      * @param dstkey 
  1228.      *            差集存入的key 
  1229.      * @param keys 
  1230.      *            可以使一个string 则返回set中所有的value 也可以是string数组 
  1231.      * @return 
  1232.      */  
  1233.     public Long sdiffstore(String dstkey, String... keys) {  
  1234.         Jedis jedis = null;  
  1235.         Long res = null;  
  1236.         try {  
  1237.             jedis = pool.getResource();  
  1238.             res = jedis.sdiffstore(dstkey, keys);  
  1239.         } catch (Exception e) {  
  1240.   
  1241.             LOGGER.error(e.getMessage());  
  1242.         } finally {  
  1243.             returnResource(pool, jedis);  
  1244.         }  
  1245.         return res;  
  1246.     }  
  1247.   
  1248.     /** 
  1249.      * <p> 
  1250.      * 通过key获取指定set中的交集 
  1251.      * </p> 
  1252.      *  
  1253.      * @param keys 
  1254.      *            可以使一个string 也可以是一个string数组 
  1255.      * @return 
  1256.      */  
  1257.     public Set<String> sinter(String... keys) {  
  1258.         Jedis jedis = null;  
  1259.         Set<String> res = null;  
  1260.         try {  
  1261.             jedis = pool.getResource();  
  1262.             res = jedis.sinter(keys);  
  1263.         } catch (Exception e) {  
  1264.   
  1265.             LOGGER.error(e.getMessage());  
  1266.         } finally {  
  1267.             returnResource(pool, jedis);  
  1268.         }  
  1269.         return res;  
  1270.     }  
  1271.   
  1272.     /** 
  1273.      * <p> 
  1274.      * 通过key获取指定set中的交集 并将结果存入新的set中 
  1275.      * </p> 
  1276.      *  
  1277.      * @param dstkey 
  1278.      * @param keys 
  1279.      *            可以使一个string 也可以是一个string数组 
  1280.      * @return 
  1281.      */  
  1282.     public Long sinterstore(String dstkey, String... keys) {  
  1283.         Jedis jedis = null;  
  1284.         Long res = null;  
  1285.         try {  
  1286.             jedis = pool.getResource();  
  1287.             res = jedis.sinterstore(dstkey, keys);  
  1288.         } catch (Exception e) {  
  1289.   
  1290.             LOGGER.error(e.getMessage());  
  1291.         } finally {  
  1292.             returnResource(pool, jedis);  
  1293.         }  
  1294.         return res;  
  1295.     }  
  1296.   
  1297.     /** 
  1298.      * <p> 
  1299.      * 通过key返回所有set的并集 
  1300.      * </p> 
  1301.      *  
  1302.      * @param keys 
  1303.      *            可以使一个string 也可以是一个string数组 
  1304.      * @return 
  1305.      */  
  1306.     public Set<String> sunion(String... keys) {  
  1307.         Jedis jedis = null;  
  1308.         Set<String> res = null;  
  1309.         try {  
  1310.             jedis = pool.getResource();  
  1311.             res = jedis.sunion(keys);  
  1312.         } catch (Exception e) {  
  1313.   
  1314.             LOGGER.error(e.getMessage());  
  1315.         } finally {  
  1316.             returnResource(pool, jedis);  
  1317.         }  
  1318.         return res;  
  1319.     }  
  1320.   
  1321.     /** 
  1322.      * <p> 
  1323.      * 通过key返回所有set的并集,并存入到新的set中 
  1324.      * </p> 
  1325.      *  
  1326.      * @param dstkey 
  1327.      * @param keys 
  1328.      *            可以使一个string 也可以是一个string数组 
  1329.      * @return 
  1330.      */  
  1331.     public Long sunionstore(String dstkey, String... keys) {  
  1332.         Jedis jedis = null;  
  1333.         Long res = null;  
  1334.         try {  
  1335.             jedis = pool.getResource();  
  1336.             res = jedis.sunionstore(dstkey, keys);  
  1337.         } catch (Exception e) {  
  1338.   
  1339.             LOGGER.error(e.getMessage());  
  1340.         } finally {  
  1341.             returnResource(pool, jedis);  
  1342.         }  
  1343.         return res;  
  1344.     }  
  1345.   
  1346.     /** 
  1347.      * <p> 
  1348.      * 通过key将set中的value移除并添加到第二个set中 
  1349.      * </p> 
  1350.      *  
  1351.      * @param srckey 
  1352.      *            需要移除的 
  1353.      * @param dstkey 
  1354.      *            添加的 
  1355.      * @param member 
  1356.      *            set中的value 
  1357.      * @return 
  1358.      */  
  1359.     public Long smove(String srckey, String dstkey, String member) {  
  1360.         Jedis jedis = null;  
  1361.         Long res = null;  
  1362.         try {  
  1363.             jedis = pool.getResource();  
  1364.             res = jedis.smove(srckey, dstkey, member);  
  1365.         } catch (Exception e) {  
  1366.   
  1367.             LOGGER.error(e.getMessage());  
  1368.         } finally {  
  1369.             returnResource(pool, jedis);  
  1370.         }  
  1371.         return res;  
  1372.     }  
  1373.   
  1374.     /** 
  1375.      * <p> 
  1376.      * 通过key获取set中value的个数 
  1377.      * </p> 
  1378.      *  
  1379.      * @param key 
  1380.      * @return 
  1381.      */  
  1382.     public Long scard(String key) {  
  1383.         Jedis jedis = null;  
  1384.         Long res = null;  
  1385.         try {  
  1386.             jedis = pool.getResource();  
  1387.             res = jedis.scard(key);  
  1388.         } catch (Exception e) {  
  1389.   
  1390.             LOGGER.error(e.getMessage());  
  1391.         } finally {  
  1392.             returnResource(pool, jedis);  
  1393.         }  
  1394.         return res;  
  1395.     }  
  1396.   
  1397.     /** 
  1398.      * <p> 
  1399.      * 通过key判断value是否是set中的元素 
  1400.      * </p> 
  1401.      *  
  1402.      * @param key 
  1403.      * @param member 
  1404.      * @return 
  1405.      */  
  1406.     public Boolean sismember(String key, String member) {  
  1407.         Jedis jedis = null;  
  1408.         Boolean res = null;  
  1409.         try {  
  1410.             jedis = pool.getResource();  
  1411.             res = jedis.sismember(key, member);  
  1412.         } catch (Exception e) {  
  1413.   
  1414.             LOGGER.error(e.getMessage());  
  1415.         } finally {  
  1416.             returnResource(pool, jedis);  
  1417.         }  
  1418.         return res;  
  1419.     }  
  1420.   
  1421.     /** 
  1422.      * <p> 
  1423.      * 通过key获取set中随机的value,不删除元素 
  1424.      * </p> 
  1425.      *  
  1426.      * @param key 
  1427.      * @return 
  1428.      */  
  1429.     public String srandmember(String key) {  
  1430.         Jedis jedis = null;  
  1431.         String res = null;  
  1432.         try {  
  1433.             jedis = pool.getResource();  
  1434.             res = jedis.srandmember(key);  
  1435.         } catch (Exception e) {  
  1436.   
  1437.             LOGGER.error(e.getMessage());  
  1438.         } finally {  
  1439.             returnResource(pool, jedis);  
  1440.         }  
  1441.         return res;  
  1442.     }  
  1443.   
  1444.     /** 
  1445.      * <p> 
  1446.      * 通过key获取set中所有的value 
  1447.      * </p> 
  1448.      *  
  1449.      * @param key 
  1450.      * @return 
  1451.      */  
  1452.     public Set<String> smembers(String key) {  
  1453.         Jedis jedis = null;  
  1454.         Set<String> res = null;  
  1455.         try {  
  1456.             jedis = pool.getResource();  
  1457.             res = jedis.smembers(key);  
  1458.         } catch (Exception e) {  
  1459.   
  1460.             LOGGER.error(e.getMessage());  
  1461.         } finally {  
  1462.             returnResource(pool, jedis);  
  1463.         }  
  1464.         return res;  
  1465.     }  
  1466.   
  1467.     /** 
  1468.      * <p> 
  1469.      * 通过key向zset中添加value,score,其中score就是用来排序的 
  1470.      * </p> 
  1471.      * <p> 
  1472.      * 如果该value已经存在则根据score更新元素 
  1473.      * </p> 
  1474.      *  
  1475.      * @param key 
  1476.      * @param score 
  1477.      * @param member 
  1478.      * @return 
  1479.      */  
  1480.     public Long zadd(String key, double score, String member) {  
  1481.         Jedis jedis = null;  
  1482.         Long res = null;  
  1483.         try {  
  1484.             jedis = pool.getResource();  
  1485.             res = jedis.zadd(key, score, member);  
  1486.         } catch (Exception e) {  
  1487.   
  1488.             LOGGER.error(e.getMessage());  
  1489.         } finally {  
  1490.             returnResource(pool, jedis);  
  1491.         }  
  1492.         return res;  
  1493.     }  
  1494.   
  1495.     /** 
  1496.      * <p> 
  1497.      * 通过key删除在zset中指定的value 
  1498.      * </p> 
  1499.      *  
  1500.      * @param key 
  1501.      * @param members 
  1502.      *            可以使一个string 也可以是一个string数组 
  1503.      * @return 
  1504.      */  
  1505.     public Long zrem(String key, String... members) {  
  1506.         Jedis jedis = null;  
  1507.         Long res = null;  
  1508.         try {  
  1509.             jedis = pool.getResource();  
  1510.             res = jedis.zrem(key, members);  
  1511.         } catch (Exception e) {  
  1512.   
  1513.             LOGGER.error(e.getMessage());  
  1514.         } finally {  
  1515.             returnResource(pool, jedis);  
  1516.         }  
  1517.         return res;  
  1518.     }  
  1519.   
  1520.     /** 
  1521.      * <p> 
  1522.      * 通过key增加该zset中value的score的值 
  1523.      * </p> 
  1524.      *  
  1525.      * @param key 
  1526.      * @param score 
  1527.      * @param member 
  1528.      * @return 
  1529.      */  
  1530.     public Double zincrby(String key, double score, String member) {  
  1531.         Jedis jedis = null;  
  1532.         Double res = null;  
  1533.         try {  
  1534.             jedis = pool.getResource();  
  1535.             res = jedis.zincrby(key, score, member);  
  1536.         } catch (Exception e) {  
  1537.   
  1538.             LOGGER.error(e.getMessage());  
  1539.         } finally {  
  1540.             returnResource(pool, jedis);  
  1541.         }  
  1542.         return res;  
  1543.     }  
  1544.   
  1545.     /** 
  1546.      * <p> 
  1547.      * 通过key返回zset中value的排名 
  1548.      * </p> 
  1549.      * <p> 
  1550.      * 下标从小到大排序 
  1551.      * </p> 
  1552.      *  
  1553.      * @param key 
  1554.      * @param member 
  1555.      * @return 
  1556.      */  
  1557.     public Long zrank(String key, String member) {  
  1558.         Jedis jedis = null;  
  1559.         Long res = null;  
  1560.         try {  
  1561.             jedis = pool.getResource();  
  1562.             res = jedis.zrank(key, member);  
  1563.         } catch (Exception e) {  
  1564.   
  1565.             LOGGER.error(e.getMessage());  
  1566.         } finally {  
  1567.             returnResource(pool, jedis);  
  1568.         }  
  1569.         return res;  
  1570.     }  
  1571.   
  1572.     /** 
  1573.      * <p> 
  1574.      * 通过key返回zset中value的排名 
  1575.      * </p> 
  1576.      * <p> 
  1577.      * 下标从大到小排序 
  1578.      * </p> 
  1579.      *  
  1580.      * @param key 
  1581.      * @param member 
  1582.      * @return 
  1583.      */  
  1584.     public Long zrevrank(String key, String member) {  
  1585.         Jedis jedis = null;  
  1586.         Long res = null;  
  1587.         try {  
  1588.             jedis = pool.getResource();  
  1589.             res = jedis.zrevrank(key, member);  
  1590.         } catch (Exception e) {  
  1591.   
  1592.             LOGGER.error(e.getMessage());  
  1593.         } finally {  
  1594.             returnResource(pool, jedis);  
  1595.         }  
  1596.         return res;  
  1597.     }  
  1598.   
  1599.     /** 
  1600.      * <p> 
  1601.      * 通过key将获取score从start到end中zset的value 
  1602.      * </p> 
  1603.      * <p> 
  1604.      * socre从大到小排序 
  1605.      * </p> 
  1606.      * <p> 
  1607.      * 当start为0 end为-1时返回全部 
  1608.      * </p> 
  1609.      *  
  1610.      * @param key 
  1611.      * @param start 
  1612.      * @param end 
  1613.      * @return 
  1614.      */  
  1615.     public Set<String> zrevrange(String key, long start, long end) {  
  1616.         Jedis jedis = null;  
  1617.         Set<String> res = null;  
  1618.         try {  
  1619.             jedis = pool.getResource();  
  1620.             res = jedis.zrevrange(key, start, end);  
  1621.         } catch (Exception e) {  
  1622.   
  1623.             LOGGER.error(e.getMessage());  
  1624.         } finally {  
  1625.             returnResource(pool, jedis);  
  1626.         }  
  1627.         return res;  
  1628.     }  
  1629.   
  1630.     /** 
  1631.      * <p> 
  1632.      * 通过key返回指定score内zset中的value 
  1633.      * </p> 
  1634.      *  
  1635.      * @param key 
  1636.      * @param max 
  1637.      * @param min 
  1638.      * @return 
  1639.      */  
  1640.     public Set<String> zrangebyscore(String key, String max, String min) {  
  1641.         Jedis jedis = null;  
  1642.         Set<String> res = null;  
  1643.         try {  
  1644.             jedis = pool.getResource();  
  1645.             res = jedis.zrevrangeByScore(key, max, min);  
  1646.         } catch (Exception e) {  
  1647.   
  1648.             LOGGER.error(e.getMessage());  
  1649.         } finally {  
  1650.             returnResource(pool, jedis);  
  1651.         }  
  1652.         return res;  
  1653.     }  
  1654.   
  1655.     /** 
  1656.      * <p> 
  1657.      * 通过key返回指定score内zset中的value 
  1658.      * </p> 
  1659.      *  
  1660.      * @param key 
  1661.      * @param max 
  1662.      * @param min 
  1663.      * @return 
  1664.      */  
  1665.     public Set<String> zrangeByScore(String key, double max, double min) {  
  1666.         Jedis jedis = null;  
  1667.         Set<String> res = null;  
  1668.         try {  
  1669.             jedis = pool.getResource();  
  1670.             res = jedis.zrevrangeByScore(key, max, min);  
  1671.         } catch (Exception e) {  
  1672.   
  1673.             LOGGER.error(e.getMessage());  
  1674.         } finally {  
  1675.             returnResource(pool, jedis);  
  1676.         }  
  1677.         return res;  
  1678.     }  
  1679.   
  1680.     /** 
  1681.      * <p> 
  1682.      * 返回指定区间内zset中value的数量 
  1683.      * </p> 
  1684.      *  
  1685.      * @param key 
  1686.      * @param min 
  1687.      * @param max 
  1688.      * @return 
  1689.      */  
  1690.     public Long zcount(String key, String min, String max) {  
  1691.         Jedis jedis = null;  
  1692.         Long res = null;  
  1693.         try {  
  1694.             jedis = pool.getResource();  
  1695.             res = jedis.zcount(key, min, max);  
  1696.         } catch (Exception e) {  
  1697.   
  1698.             LOGGER.error(e.getMessage());  
  1699.         } finally {  
  1700.             returnResource(pool, jedis);  
  1701.         }  
  1702.         return res;  
  1703.     }  
  1704.   
  1705.     /** 
  1706.      * <p> 
  1707.      * 通过key返回zset中的value个数 
  1708.      * </p> 
  1709.      *  
  1710.      * @param key 
  1711.      * @return 
  1712.      */  
  1713.     public Long zcard(String key) {  
  1714.         Jedis jedis = null;  
  1715.         Long res = null;  
  1716.         try {  
  1717.             jedis = pool.getResource();  
  1718.             res = jedis.zcard(key);  
  1719.         } catch (Exception e) {  
  1720.   
  1721.             LOGGER.error(e.getMessage());  
  1722.         } finally {  
  1723.             returnResource(pool, jedis);  
  1724.         }  
  1725.         return res;  
  1726.     }  
  1727.   
  1728.     /** 
  1729.      * <p> 
  1730.      * 通过key获取zset中value的score值 
  1731.      * </p> 
  1732.      *  
  1733.      * @param key 
  1734.      * @param member 
  1735.      * @return 
  1736.      */  
  1737.     public Double zscore(String key, String member) {  
  1738.         Jedis jedis = null;  
  1739.         Double res = null;  
  1740.         try {  
  1741.             jedis = pool.getResource();  
  1742.             res = jedis.zscore(key, member);  
  1743.         } catch (Exception e) {  
  1744.   
  1745.             LOGGER.error(e.getMessage());  
  1746.         } finally {  
  1747.             returnResource(pool, jedis);  
  1748.         }  
  1749.         return res;  
  1750.     }  
  1751.   
  1752.     /** 
  1753.      * <p> 
  1754.      * 通过key删除给定区间内的元素 
  1755.      * </p> 
  1756.      *  
  1757.      * @param key 
  1758.      * @param start 
  1759.      * @param end 
  1760.      * @return 
  1761.      */  
  1762.     public Long zremrangeByRank(String key, long start, long end) {  
  1763.         Jedis jedis = null;  
  1764.         Long res = null;  
  1765.         try {  
  1766.             jedis = pool.getResource();  
  1767.             res = jedis.zremrangeByRank(key, start, end);  
  1768.         } catch (Exception e) {  
  1769.   
  1770.             LOGGER.error(e.getMessage());  
  1771.         } finally {  
  1772.             returnResource(pool, jedis);  
  1773.         }  
  1774.         return res;  
  1775.     }  
  1776.   
  1777.     /** 
  1778.      * <p> 
  1779.      * 通过key删除指定score内的元素 
  1780.      * </p> 
  1781.      *  
  1782.      * @param key 
  1783.      * @param start 
  1784.      * @param end 
  1785.      * @return 
  1786.      */  
  1787.     public Long zremrangeByScore(String key, double start, double end) {  
  1788.         Jedis jedis = null;  
  1789.         Long res = null;  
  1790.         try {  
  1791.             jedis = pool.getResource();  
  1792.             res = jedis.zremrangeByScore(key, start, end);  
  1793.         } catch (Exception e) {  
  1794.   
  1795.             LOGGER.error(e.getMessage());  
  1796.         } finally {  
  1797.             returnResource(pool, jedis);  
  1798.         }  
  1799.         return res;  
  1800.     }  
  1801.   
  1802.     /** 
  1803.      * <p> 
  1804.      * 返回满足pattern表达式的所有key 
  1805.      * </p> 
  1806.      * <p> 
  1807.      * keys(*) 
  1808.      * </p> 
  1809.      * <p> 
  1810.      * 返回所有的key 
  1811.      * </p> 
  1812.      *  
  1813.      * @param pattern 
  1814.      * @return 
  1815.      */  
  1816.     public Set<String> keys(String pattern) {  
  1817.         Jedis jedis = null;  
  1818.         Set<String> res = null;  
  1819.         try {  
  1820.             jedis = pool.getResource();  
  1821.             res = jedis.keys(pattern);  
  1822.         } catch (Exception e) {  
  1823.   
  1824.             LOGGER.error(e.getMessage());  
  1825.         } finally {  
  1826.             returnResource(pool, jedis);  
  1827.         }  
  1828.         return res;  
  1829.     }  
  1830.   
  1831.     /** 
  1832.      * <p> 
  1833.      * 通过key判断值得类型 
  1834.      * </p> 
  1835.      *  
  1836.      * @param key 
  1837.      * @return 
  1838.      */  
  1839.     public String type(String key) {  
  1840.         Jedis jedis = null;  
  1841.         String res = null;  
  1842.         try {  
  1843.             jedis = pool.getResource();  
  1844.             res = jedis.type(key);  
  1845.         } catch (Exception e) {  
  1846.   
  1847.             LOGGER.error(e.getMessage());  
  1848.         } finally {  
  1849.             returnResource(pool, jedis);  
  1850.         }  
  1851.         return res;  
  1852.     }  
  1853.   
  1854.     /** 
  1855.      * 返还到连接池 
  1856.      * 
  1857.      * @param pool 
  1858.      * @param jedis 
  1859.      */  
  1860.     public static void returnResource(JedisPool pool, Jedis jedis) {  
  1861.         if (jedis != null) {  
  1862.             pool.returnResourceObject(jedis);  
  1863.         }  
  1864.     }  
  1865.   
  1866.     /** 
  1867.      * 返还到连接池 
  1868.      * 
  1869.      * @param pool 
  1870.      * @param jedis 
  1871.      */  
  1872.     public static void returnResource(Jedis jedis) {  
  1873.         if (jedis != null) {  
  1874.             pool.returnResourceObject(jedis);  
  1875.         }  
  1876.     }  
  1877. }  

4、测试

写了一个简单的秒杀系统的模拟

[java]  view plain  copy
  1. package com.github.distribute.lock.redis;  
  2.   
  3. import java.util.Set;  
  4. import java.util.concurrent.ExecutorService;  
  5. import java.util.concurrent.Executors;  
  6. import java.util.concurrent.TimeUnit;  
  7.   
  8. import redis.clients.jedis.Jedis;  
  9.   
  10. public class PessimisticLockTest {  
  11.   
  12.     public static void main(String[] args) {  
  13.         long starTime=System.currentTimeMillis();  
  14.           
  15.         initPrduct();  
  16.         initClient();  
  17.         printResult();  
  18.            
  19.         long endTime=System.currentTimeMillis();  
  20.         long Time=endTime-starTime;  
  21.         System.out.println("程序运行时间: "+Time+"ms");     
  22.     }  
  23.   
  24.     /** 
  25.      * 输出结果 
  26.      */  
  27.     public static void printResult() {  
  28.         Jedis jedis = RedisUtil.getInstance().getJedis();  
  29.         Set<String> set = jedis.smembers("clientList");  
  30.   
  31.         int i = 1;  
  32.         for (String value : set) {  
  33.             System.out.println("第" + i++ + "个抢到商品," + value + " ");  
  34.         }  
  35.   
  36.         RedisUtil.returnResource(jedis);  
  37.     }  
  38.   
  39.     /* 
  40.      * 初始化顾客开始抢商品 
  41.      */  
  42.     public static void initClient() {  
  43.         ExecutorService cachedThreadPool = Executors.newCachedThreadPool();  
  44.         int clientNum = 10000;// 模拟客户数目  
  45.         for (int i = 0; i < clientNum; i++) {  
  46.             cachedThreadPool.execute(new PessClientThread(i));  
  47.         }  
  48.         cachedThreadPool.shutdown();  
  49.   
  50.         while (true) {  
  51.             if (cachedThreadPool.isTerminated()) {  
  52.                 System.out.println("所有的线程都结束了!");  
  53.                 break;  
  54.             }  
  55.             try {  
  56.                 Thread.sleep(1000);  
  57.             } catch (InterruptedException e) {  
  58.                 e.printStackTrace();  
  59.             }  
  60.         }  
  61.     }  
  62.   
  63.     /** 
  64.      * 初始化商品个数 
  65.      */  
  66.     public static void initPrduct() {  
  67.         int prdNum = 100;// 商品个数  
  68.         String key = "prdNum";  
  69.         String clientList = "clientList";// 抢购到商品的顾客列表  
  70.         Jedis jedis = RedisUtil.getInstance().getJedis();  
  71.   
  72.         if (jedis.exists(key)) {  
  73.             jedis.del(key);  
  74.         }  
  75.   
  76.         if (jedis.exists(clientList)) {  
  77.             jedis.del(clientList);  
  78.         }  
  79.   
  80.         jedis.set(key, String.valueOf(prdNum));// 初始化  
  81.         RedisUtil.returnResource(jedis);  
  82.     }  
  83.   
  84. }  
  85.   
  86. /** 
  87.  * 顾客线程 
  88.  *  
  89.  * @author linbingwen 
  90.  * 
  91.  */  
  92. class PessClientThread implements Runnable {  
  93.     String key = "prdNum";// 商品主键  
  94.     String clientList = "clientList";// // 抢购到商品的顾客列表主键  
  95.     String clientName;  
  96.     RedisBasedDistributedLock redisBasedDistributedLock;  
  97.     Jedis jedis = null;  
  98.   
  99.     public PessClientThread(int num) {  
  100.         clientName = "编号=" + num;  
  101.         init();  
  102.     }  
  103.   
  104.     public void init() {  
  105.         jedis = RedisUtil.getInstance().getJedis();  
  106.         redisBasedDistributedLock = new RedisBasedDistributedLock(jedis, "lock.lock"5 * 1000);  
  107.     }  
  108.   
  109.     public void run() {  
  110.         try {  
  111.             Thread.sleep((int) (Math.random() * 5000));// 随机睡眠一下  
  112.         } catch (InterruptedException e1) {  
  113.         }  
  114.   
  115.         while (true) {  
  116.             //先判断缓存是否有商品  
  117.             if(Integer.valueOf(jedis.get(key))<= 0) {  
  118.                 break;  
  119.             }  
  120.               
  121.             //缓存还有商品,取锁,商品数目减去1  
  122.             System.out.println("顾客:" + clientName + "开始抢商品");  
  123.             if (redisBasedDistributedLock.tryLock(3,TimeUnit.SECONDS)) { //等待3秒获取锁,否则返回false  
  124.                 int prdNum = Integer.valueOf(jedis.get(key)); //再次取得商品缓存数目  
  125.                 if (prdNum > 0) {  
  126.                     jedis.decr(key);//商品数减1  
  127.                     jedis.sadd(clientList, clientName);// 抢到商品记录一下  
  128.                     System.out.println("好高兴,顾客:" + clientName + "抢到商品");  
  129.                 } else {  
  130.                     System.out.println("悲剧了,库存为0,顾客:" + clientName + "没有抢到商品");  
  131.                 }  
  132.                 redisBasedDistributedLock.unlock();  
  133.                 break;  
  134.             }  
  135.         }  
  136.         //释放资源  
  137.         redisBasedDistributedLock = null;  
  138.         RedisUtil.returnResource(jedis);  
  139.     }  
  140.   
  141. }  

输出结果:



本文源码请在这里下载:https://github.com/appleappleapple/DistributeLearning


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mybatis-plus乐观锁和Redis分布式锁都是用于解决并发访问数据时的线程安全问题,但它们的实现方式和应用场景有所不同。 Mybatis-plus乐观锁是基于数据库的乐观实现机制,通过在数据表中添加一个版本号字段来实现。当多个线程同时访问同一条数据时,每个线程会读取到这个版本号,并在更新时将版本号作为更新条件,如果版本号匹配,则执行更新操作;如果版本号不匹配,则说明其他线程已经修改了数据,当前线程更新失败。乐观锁适用于高并发读取、低并发更新的场景,可以减少数据库的锁冲突,提高并发性能。 Redis分布式锁是基于Redis实现的一种分布式锁机制。通过在Redis中设置一个特定的key作为锁,在获取锁时判断该key是否存在,如果存在则表示锁已被其他线程占用,当前线程需要等待;如果不存在,则表示当前线程获取到了锁,可以执行业务操作。分布式锁适用于分布式环境下的并发控制,可以保证多个节点之间的数据一致性和并发安全。 对比而言,Mybatis-plus乐观锁是在数据库层面实现的,适用于单个数据库实例的并发控制,可以减少数据库的锁冲突,但并不能解决分布式环境下的并发问题。而Redis分布式锁则是基于Redis实现的,适用于分布式环境下的并发控制,可以保证多个节点之间的数据一致性和并发安全。 在实际应用中,选择使用哪种机制还需要根据具体场景和需求来决定。如果是单个数据库实例的并发控制,可以选择Mybatis-plus乐观锁;如果是分布式环境下的并发控制,可以选择Redis分布式锁

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值