使用Redis如何实现分布式锁?

来源:互联网 发布:如何设计算法 编辑:程序博客网 时间:2024/06/04 19:17

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

  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成功,表示成功获取锁。

  其他的线程在setlockName时被阻塞直到超时。

  *

  @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) {

  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:对lockNamewatch,开启一个事务,删除以LockNamekey的锁,删除后,此锁对于其他线程为可争抢的。

  *

  @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");

  }

  }

  }

 

来源:BridgeLi's Blog

0 0
原创粉丝点击