用redis实现分布式锁,秒杀案例

  • 时间:
  • 浏览:0
  • 来源:跟我学网络



分布式锁的简单实现代码:

/** * 分布式锁的简单实现代码 * Created by liuyang on 2017/4/20. */ public class

DistributedLock { private final JedisPool jedisPool; public DistributedLock

(JedisPool jedisPool) {this.jedisPool = jedisPool; } /** * 加锁 * @param lockName

锁的key * @param acquireTimeout 获取超时时间 * @param timeout 锁的超时时间 * @return 锁标识 */

public String lockWithTimeout(String lockName, long acquireTimeout, long

timeout) { Jedis conn =null; String retIdentifier = null; try { // 获取连接 conn =

jedisPool.getResource();// 随机生成一个value String identifier =

UUID.randomUUID().toString();// 锁名,即key值 String lockKey = "lock:" + lockName;

// 超时时间,上锁后超过此时间则自动释放锁 int lockExpire = (int) (timeout / 1000); //

获取锁的超时时间,超过这个时间则放弃获取锁 long end = System.currentTimeMillis() + acquireTimeout;

while (System.currentTimeMillis() < end) { if (conn.setnx(lockKey, identifier)

==1) { conn.expire(lockKey, lockExpire); // 返回value值,用于释放锁时间确认 retIdentifier =

identifier;return retIdentifier; } // 返回-1代表key没有设置超时时间,为key设置一个超时时间 if

(conn.ttl(lockKey) == -1) { conn.expire(lockKey, lockExpire); } try {

Thread.sleep(10); } catch (InterruptedException e) {

Thread.currentThread().interrupt(); } } }catch (JedisException e) {

e.printStackTrace(); }finally { if (conn != null) { conn.close(); } } return

retIdentifier; }/** * 释放锁 * @param lockName 锁的key * @param identifier 释放锁的标识 *

@return */ public boolean releaseLock(String lockName, String identifier) {

Jedis conn =null; String lockKey = "lock:" + lockName; boolean retFlag = false;

try { conn = jedisPool.getResource(); while (true) { // 监视lock,准备开始事务

conn.watch(lockKey);// 通过前面返回的value值判断是不是该锁,若是该锁,则删除,释放锁 if

(identifier.equals(conn.get(lockKey))) { Transaction transaction =

conn.multi(); transaction.del(lockKey); List<Object> results =

transaction.exec();if (results == null) { continue; } retFlag = true; }

conn.unwatch();break; } } catch (JedisException e) { e.printStackTrace(); }

finally { if (conn != null) { conn.close(); } } return retFlag; } }

*

测试刚才实现的分布式锁

例子中使用50个线程模拟秒杀一个商品,使用–运算符来实现商品减少,从结果有序性就可以看出是否为加锁状态。

模拟秒杀服务,在其中配置了jedis线程池,在初始化的时候传给分布式锁,供其使用。



/** * Created by liuyang on 2017/4/20. */ public class Service { private static

JedisPool pool =null; private DistributedLock lock = new DistributedLock(pool);

int n = 500; static { JedisPoolConfig config = new JedisPoolConfig(); // 设置最大连接数

config.setMaxTotal(200); // 设置最大空闲数 config.setMaxIdle(8); // 设置最大等待时间

config.setMaxWaitMillis(1000 * 100); //

在borrow一个jedis实例时,是否需要验证,若为true,则所有jedis实例均是可用的 config.setTestOnBorrow(true);

pool =new JedisPool(config, "127.0.0.1", 6379, 3000); } public void seckill() {

// 返回锁的value值,供释放锁时候进行判断 String identifier = lock.lockWithTimeout("resource",

5000, 1000); System.out.println(Thread.currentThread().getName() + "获得了锁");

System.out.println(--n); lock.releaseLock("resource", identifier); } }

模拟线程进行秒杀服务:

public class ThreadA extends Thread { private Service service; public ThreadA

(Service service) {this.service = service; } @Override public void run() {

service.seckill(); } }public class Test { public static void main(String[]

args) { Service service =new Service(); for (int i = 0; i < 50; i++) { ThreadA

threadA =new ThreadA(service); threadA.start(); } } }

结果如下,结果为有序的:

若注释掉使用锁的部分:



public void seckill() { // 返回锁的value值,供释放锁时候进行判断 //String indentifier = lock

.lockWithTimeout("resource", 5000, 1000); System.out.println(Thread

.currentThread().getName() + "获得了锁"); System.out.println(--n); //lock

.releaseLock("resource", indentifier); }

从结果可以看出,有一些是异步进行的: