大家都知道Redis是NoSQL的一种,目前在互联网公司中在作为缓存广泛的使用者,其实利用Redis的setnx还可以快速实现一个分布式锁,公司的业务就需要使用分布式锁保证数据的唯一性,经检索在网上发现已经有活雷锋分享了一套,本着不在重新发明轮子的想法,测试了一下好像没有问题,几乎不用对原代码进行修改,就能使用,下面就分享在这里,供需要的朋友参考。原文里面还有对实现的原理进行解释,所以本文就不再赘述,详情请通过参考资料进行访问。

package cn.bridgeli.distributedlock;

import java.util.UUID;  
import java.util.concurrent.CountDownLatch;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;

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

public class RedisDistributedLock {

  private static final Logger LOG = LoggerFactory.getLogger(RedisDistributedLock.class);

  private static final String redisHost = "127.0.0.1";

  private static final int port = 6381;

  private static JedisPoolConfig config;

  private static JedisPool pool;

  private static ExecutorService service;

  private static int ThLeng = 10;

  private static CountDownLatch latch;

  private static AtomicInteger Countor = new AtomicInteger(0);

  private static int count = 0;

  private static String LockName = "mylock_test10";

  static {  
    // 利用Redis连接池,保证多个线程利用多个连接,充分模拟并发性  
    config = new JedisPoolConfig();  
    config.setMaxIdle(10);  
    config.setMaxWaitMillis(1000);  
    config.setMaxTotal(30);  
    pool = new JedisPool(config, redisHost, port);  
    // 利用ExecutorService 管理线程  
    service = Executors.newFixedThreadPool(ThLeng);  
    // CountDownLatch保证主线程在全部线程结束之后退出  
    latch = new CountDownLatch(ThLeng);  
  }

  /**  
   * 获取锁 tips:生成一个UUID,作为Key的标识,不断轮询lockName,直到set成功,表示成功获取锁。  
   * 其他的线程在set此lockName时被阻塞直到超时。  
   *  
   * @param pool  
   * @param lockName  
   * @param timeouts  
   * @return 锁标志  
   */  
  public static String getLock(JedisPool pool, String lockName, long timeouts) {  
    Jedis client = pool.getResource();  
    try {  
      String value = UUID.randomUUID().toString();  
      long timeWait = System.currentTimeMillis() + timeouts * 1000;  
      while (System.currentTimeMillis() < timeWait) {  
        if (client.setnx(lockName, value) == 1) {  
          // 防止key卡死,一直不释放锁,所以1800s过期  
          client.expire(lockName, 1800);  
          LOG.info("lock geted");  
          return value;  
        }  
        try {  
          Thread.sleep(1000);  
        } catch (InterruptedException e) {  
          e.printStackTrace();  
        }  
        LOG.info("get lock timeouts");  
      } finally {  
        // pool.returnBrokenResource(client);  
        pool.returnResource(client);  
      }  
    }
    return null;  
  }

  /**  
   * 释放锁 tips:对lockName做watch,开启一个事务,删除以LockName为key的锁,删除后,此锁对于其他线程为可争抢的。  
   *  
   * @param pool  
   * @param lockName  
   * @param value  
   */  
  public static void relaseLock(JedisPool pool, String lockName, String value) {  
    Jedis client = pool.getResource();  
    try {  
      while (true) {  
        client.watch(lockName);  
        if (client.get(lockName).equals(value)) {  
          Transaction tx = client.multi();  
          tx.del(lockName);  
          tx.exec();  
          return;  
        }  
        client.unwatch();  
      } finally {  
        // pool.returnBrokenResource(client);  
        pool.returnResource(client);  
      }  
    }
  }

  public static void main(String args[]) {  
    for (int i = 0; i < ThLeng; i++) {  
      String tName = "thread-" + i;  
      Thread t = new Thread(new SubAddThread(pool, tName));  
      LOG.info(tName + "inited...");  
      service.submit(t);  
    }
    service.shutdown();  
    try {  
      latch.await();  
    } catch (InterruptedException e) {  
      e.printStackTrace();  
    }
    LOG.info(Countor.get() + "");  
    LOG.info(count + "");  
  }
}
public static class SubAddThread implements Runnable {

  private String name;

  private JedisPool pool;

  public SubAddThread(JedisPool pool, String uname) {  
    this.pool = pool;  
    this.name = uname;  
  }

  @Override  
  public void run() {  
    for (int i = 0; i < 100; i++) {  
      LOG.info(name + " starting...");  
      String valuse = getLock(pool, LockName, 50);  
      LOG.info(name + " get Lock " + valuse);  
      count++;  
      relaseLock(pool, LockName, valuse);  
      Countor.incrementAndGet();  
      LOG.info(name + " " + count);  
    }
    latch.countDown();  
    LOG.info(name + " complated");  
  }
}

参考资料:http://www.jianshu.com/p/c1f5d26cb1c9