#基于开源项目天机学堂的学习#
Redission
Redission解决的问题:
原子性:多线程下锁标识与锁的获取释放。
超时问题:超时释放易在阻塞发生时出错。
不可重入:一个线程获取锁后再次获取锁不成功。
失败重试:获取锁后是快速结束还是重新获取锁的动态实现。
一致性问题:主从同步时的一致性没有实现,如主节点获取锁宕机了,从节点成为主后没有锁信息。
锁获取使用:
@Autowired
private RedissonClient redissonClient;
@Test
void testRedisson() throws InterruptedException{
//1.获取锁对象,指定锁名称
RLock lock=redissonClient.getLock("lockname");
try{
//2.尝试获取锁
boolean isLock=lock.tryLock(1,10,TimeUnit.SECONDS);
if(!isLock){
//获取锁失败处理
}else{
//获取锁成功处理
}
}finally{
//4.释放锁
lock.unlock();
}
}
使用简单工厂来优化获取锁逻辑:
//1.获取锁对象,指定锁名称
RLock lock=redissonClient.getLock("lockname");
自定义工厂为MyLockFactory,然后将bean注入到类中。
工厂中使用了可重入锁、公平锁、读写锁。
@Component
public class MyLockFactory {
private final Map<MyLockType, Function<String,RLock>> lockHandlers;
public MyLockFactory(RedissonClient redissonClient){
// this.lockHandlers=new HashMap<>((MyLockType.values().length);
//此处用EnumMap代替HashMap,因为枚举map的key是枚举,能大大提高根据枚举取value的效率
this.lockHandlers=new EnumMap<>(MyLockType.class);
this.lockHandlers.put(MyLockType.RE_ENTRANT_LOCK,redissonClient::getLock);
this.lockHandlers.put(MyLockType.FAIR_LOCK,redissonClient::getFairLock);
this.lockHandlers.put(MyLockType.READ_LOCK,name->redissonClient.getReadWriteLock(name).readLock());
this.lockHandlers.put(MyLockType.WRITE_LOCK,name->redissonClient.getReadWriteLock(name).writeLock());
}
public RLock getLock(MyLockType lockType,String name){
return lockHandlers.get(lockType).apply(name);
}
}
public enum MyLockType {
RE_ENTRANT_LOCK,
FAIR_LOCK,
READ_LOCK,
WRITE_LOCK,
;
}
使用策略模式来优化获取锁失败的逻辑:
//2.尝试获取锁
boolean isLock=lock.tryLock(1,10,TimeUnit.SECONDS);
此处五种策略应写五个类来实现,由于代码逻辑较简单,就直接写出,类似于匿名内部类的写法
public enum MyLockStrategy {
SKIP_FAST(){ //快速结束
@Override
public boolean tryLock(RLock lock, MyLock prop) throws InterruptedException {
return lock.tryLock(0, prop.leaseTime(), prop.unit());
}
},
FAIL_FAST(){ //快速失败
@Override
public boolean tryLock(RLock lock, MyLock prop) throws InterruptedException {
boolean islock= lock.tryLock(0, prop.leaseTime(), prop.unit());
if(!islock){
throw new BizIllegalException("请求太频繁");
}
return true;
}
},
KEEP_TRYING(){ //保持重试
@Override
public boolean tryLock(RLock lock, MyLock prop) {
lock.lock( prop.leaseTime(), prop.unit());
return true;
}
},
SKIP_AFTER_RETRY_TIMEOUT(){ //重试超时后结束
@Override
public boolean tryLock(RLock lock, MyLock prop) throws InterruptedException {
return lock.tryLock(prop.waitTime(), prop.leaseTime(), prop.unit());
}
},
FAIL_AFTER_RETRY_TIMEOUT(){ //重试超时后抛出异常
@Override
public boolean tryLock(RLock lock, MyLock prop) throws InterruptedException {
boolean islock= lock.tryLock(prop.waitTime(), prop.leaseTime(), prop.unit());
if(!islock){
throw new BizIllegalException("请求太频繁");
}
return true;
}
},
;
public abstract boolean tryLock(RLock lock,MyLock prop) throws InterruptedException;
然后我们就可以指出需要的锁及锁获取失败逻辑。
//自定义的MyLock mylock 中指定了
//MyLockType lockType() default MyLockType.RE_ENTRANT_LOCK;
//MyLockStrategy lockStrategy() default MyLockStrategy.FAIL_AFTER_RETRY_TIMEOUT;
//1.创建锁对象
RLock lock=lockFactory.getLock(myLock.lockType(),myLock.name());
//2.尝试获取锁
boolean isLock=myLock.lockStrategy().tryLock(lock,myLock);