锁要达到的效果
在实际的业务逻辑中,不需要去考虑能不能获取到锁
A线程在使用锁(锁尚未被A线程释放),而B线程执行了获取锁,这时B线程有两种处理:
①、未能获取到锁,逻辑退出;
②、利用循环逻辑不停的获取锁,直到得到锁,继续后面的逻辑
实际的业务逻辑中,不需要考虑锁的释放问题
只需要要执行获取锁就可以了,锁自动释放
锁封装处理
①.Redis操作封装类
/**
* Redis访问封装
* @author chester
*
*/
@Component
public class RedisService {
@Autowired
private JedisPool jedisPool;
public JedisPool getJedisPool() {
return jedisPool;
}
public <T> T callJedis(ICallJedis<T> icallJedis) {
final Jedis jedis = jedisPool.getResource();
try {
return icallJedis.call(jedis);
}catch (Exception e) {
LogUtil.error(ExceptionUtils.getStackFrames(e));
} finally {
jedis.close();
}
throw new RuntimeException("请求Redis出错!!!");
}
public static interface ICallJedis<T> {
public T call(Jedis jedis);
}
/**
* Redis Incr 命令将 key 中储存的数字值增一。
* 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
* @param key
* @return
*/
public Long incr(String key) {
return callJedis(new ICallJedis<Long>() {
@Override
public Long call(Jedis jedis) {
return jedis.incr(key);
}
});
}
public Long pexpire(String key,long milliseconds) {
return callJedis(new ICallJedis<Long>() {
@Override
public Long call(Jedis jedis) {
return jedis.pexpire(key, milliseconds);
}
});
}
//TODO 其他操作封装未贴出
}
②.Redis锁封装
/**
* 用Redis封装的锁,用于修改数据
* @author chester
*
*/
public class RedisLock {
//taskExecutor 可根据实际情况,利用项目中的线程
private static ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
//锁的Key
private String lockKey;
//锁过期时间
private int expireTime;
//redis客户端
private RedisService redisService;
//业务逻辑在此接口中执行
public static interface IProcesser{
public void process() throws Exception;
}
public RedisLock(RedisService redisService,long rid,String category) {
this(redisService, rid, category, 2000);
}
public RedisLock(RedisService redisService,long rid,String category,int milliseconds) {
this.lockKey = "RedisLock_"+rid+"_"+category;
this.redisService = redisService;
this.expireTime = milliseconds;
}
/**
* 获取锁
* @return
*/
public boolean get() {
CountDownLatch countDownLatch = new CountDownLatch(1);
taskExecutor.execute(new Worker(countDownLatch));
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
public void release() {
redisService.del(lockKey);
}
/**
* 利用此函数执行业务逻辑
* @param iProcesser
* @throws Exception
*/
public void process(IProcesser iProcesser) throws Exception{
if(get()) {
try {
iProcesser.process();
} finally {
release();
}
}
}
//保证获取到锁
private class Worker implements Runnable{
private CountDownLatch countDownLatch;
Worker(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
public void run() {
while (true) {
boolean ok = (redisService.incr(lockKey) == 1);
if(ok) {
redisService.pexpire(lockKey, (long)expireTime);
countDownLatch.countDown();
break;
}
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
项目使用
//针对rid创建不同类型的锁
new RedisLock(redisService, rid, RedisLockCategory).process(new RedisLock.IProcesser() {
@Override
public void process() throws LangException {
//TODO 实际项目中的业务逻辑
}
});
网友评论