redis分布式锁和调度锁

简单好用-redis分布式锁实现

RedisLock
package com.pingan.toa.asset.common.utils.redis;
import java.util.Random;

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

/**
 * @author macow
 */
public class RedisLock {
    //加锁标志
    public static final String LOCKED = "TRUE";
    public static final long ONE_MILLI_NANOS = 1000000L;
    //默认超时时间(毫秒)
    public static final long DEFAULT_TIME_OUT = 3000;
    public static JedisPool pool;
    public static final Random r = new Random();
    //锁的超时时间(秒),过期删除
    public static final int EXPIRE = 5 * 60;
    static {
        pool = new JedisPool(new JedisPoolConfig(), "host", 6379);
    }
    private Jedis jedis;
    private String key;
    //锁状态标志
    private boolean locked = false;

    public RedisLock(String key) {
        this.key = key;
        this.jedis = pool.getResource();
    }

    public boolean lock(long timeout) {
        long nano = System.nanoTime();
        timeout *= ONE_MILLI_NANOS;
        try {
            while ((System.nanoTime() - nano) < timeout) {
                if (jedis.setnx(key, LOCKED) == 1) {
                    jedis.expire(key, EXPIRE);
                    locked = true;
                    return locked;
                }
                // 短暂休眠,nano避免出现活锁
                Thread.sleep(3, r.nextInt(500));
            }
        } catch (Exception e) {
        }
        return false;
    }
    public boolean lock() {
        return lock(DEFAULT_TIME_OUT);
    }

    // 无论是否加锁成功,必须调用
    public void unlock() {
        try {
            if (locked)
                jedis.del(key);
        } finally {
            pool.returnResource(jedis);
        }
    }
}

工具类版,修改版

RedisSimpleLockUtils.java

package com.pingan.toa.asset.common.utils.redis;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

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

import redis.clients.jedis.ShardedJedis;

/**
 * Redis分布式锁
 * @author WEIJIA625
 */
public class RedisSimpleLockUtils {

	private static Logger logger = LoggerFactory.getLogger(RedisSimpleLockUtils.class);
	// 加锁标志
	public 	static final String LOCKED_TIME = SimpleDateFormat.getDateTimeInstance().format(new Date());
	//1毫秒=1000 000纳秒
	public 	static final long ONE_MILLI_NANOS = 1000000L;
	// 默认超时时间(毫秒)
	public 	static final long DEFAULT_TIME_OUT = 1 * 1000;
	public 	static final Random r = new Random();
	// 锁的超时时间(秒),过期删除
	public 	static final int EXPIRE = 5 * 60;


	/**
	 * 	获取分布式锁
	 * @param lockedKey 
	 * 			建议业务名称+业务主键
	 * @param timeout
	 * 			获取分布式锁的超时时间(毫秒)
	 * @return
	 * 			true:获取锁成功,fasle:获取锁失败
	 */
	public static boolean lock(String lockedKey,long timeout) {
		ShardedJedis shardedJedis = ShardedRedisUtil.getPool().getResource();
		try {
			long nano = System.nanoTime();
			long timeoutNanos =timeout * ONE_MILLI_NANOS;
			while ((System.nanoTime() - nano) < timeoutNanos) {
				if (shardedJedis.setnx(lockedKey, LOCKED_TIME) == 1) {
					shardedJedis.expire(lockedKey, EXPIRE);
					logger.info("RedisSimpleLockUtils.lock-->lockedKey=‘{}’ , timeout={}毫秒",lockedKey,timeout);
					return true;
				}
				// 短暂休眠,nano避免出现活锁
				Thread.sleep(2, r.nextInt(500));
			}
		} catch (Exception e) {
			ShardedRedisUtil.getPool().returnBrokenResource(shardedJedis);
			e.printStackTrace();
		} finally {
			ShardedRedisUtil.getPool().returnResource(shardedJedis);
		}
		return false;
	}
	/**
	 * 	获取分布式锁
	 * @param lockedKey 
	 * 			建议业务名称+业务主键
	 * @return
	 * 			true:获取锁成功,fasle:获取锁失败
	 */
	public static boolean lock(String lockedKey) {
		return lock(lockedKey,6);
	}
	
	/**
	 * 获取调度锁
	 * 		注意点:1.无需释放锁;2.任务调度周期>5分钟  && 任务处理耗时 > 1秒
	 * @param lockedKey 
	 * 		调度锁的key
	 * @return 
	 * 		true:获取锁成功,fasle:获取锁失败
	 * 
	 * @desc 
	 *  	instanceMaxDiffTime:集群下各实例所在应用服务器的最大时间差
	 * 		timeout:超时时间,默认为1秒
	 * 		tasktime:任务执行所需时间
	 * 		expireTime:锁有效时间,默认为5分钟
	 * 		scheduletime:调度周期
	 * 		调度锁有效条件: 0<=instanceMaxDiffTime<timeout<tasktime<expireTime<scheduletime
	 * 		此方法默认不调用解锁下,锁的有效条件:1秒<tasktime<5分钟<scheduletime
	 */
	public static boolean scheduleLock(String lockedKey) {
		return lock(lockedKey,DEFAULT_TIME_OUT);
	}

	/**
	 * 释放分布式锁
	 * @param lockedKey
	 * 		建议业务名称+业务主键
	 */
	public static void unlock(String lockedKey) {
		ShardedJedis shardedJedis = ShardedRedisUtil.getPool().getResource();
		try {
			Long del = shardedJedis.del(lockedKey);
			logger.info("RedisSimpleLockUtils.unlock-->lockedKey=‘{}’ ,del lock={}",lockedKey,del);
		}catch (Exception e) {
			ShardedRedisUtil.getPool().returnBrokenResource(shardedJedis);
		}  finally {
			ShardedRedisUtil.getPool().returnResource(shardedJedis);
		}
	}
	
	/**
	 * 测试辅助类
	 * @author WEIJIA625
	 *
	 */
	 static class TaskWork{
		
		public void scheduleWork(){
			if(!RedisSimpleLockUtils.scheduleLock("doWork")) {return;}
			logger.info("@@@---@@@>{} dowork start",Thread.currentThread().getName());
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			logger.info("###---###>{} dowork end",Thread.currentThread().getName());
		}
		public void secondKill(){
			if(!RedisSimpleLockUtils.lock("doWork")) {return;}
			logger.info("@@@---@@@>{} dowork start",Thread.currentThread().getName());
			try {
				Thread.sleep(new Random().nextInt(50));
				logger.info("###---###>{} dowork end",Thread.currentThread().getName());
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				RedisSimpleLockUtils.unlock("doWork");
			}
		}
	}
	
	public static void main(String[] args) {
		//测试类见:RedisSimpleLockUtilsTest.java
	}
}


测试类
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.pingan.toa.asset.common.utils.redis.RedisSimpleLockUtils.TaskWork;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring-context.xml")
public class RedisSimpleLockUtilsTest {
	

	@Test
	public void testScheduleWork() {
		ExecutorService pool= Executors.newFixedThreadPool(20);
		final TaskWork task=new TaskWork();
		for(int i=0;i<10;i++){
			pool.execute(new Runnable() {
				@Override
				public void run() {
					while (true) {
						task.scheduleWork();
					}
				}
			});
		}
		
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	@Test
	public void testSecondKill() {
		ExecutorService pool= Executors.newFixedThreadPool(50);
		final TaskWork task=new TaskWork();
		for(int i=0;i<10;i++){
			pool.execute(new Runnable() {
				@Override
				public void run() {
					while (true) {
						task.secondKill();;
					}
				}
			});
		}
		
		try {
			Thread.sleep(100000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值