Redisson PermitExpirableSemaphore源码详解
这两天的工作中发现了一个问题。原本一直在使用的redisson提供的semaphore信号量经常会莫名其妙的消失,也就是所谓的信号量泄露,发现问题出在调用的外部服务上,所以我只能试图通过给semaphore的每个信号量设置过期时间,也就是说当获取一个信号量的时候,如果在一定时间内没有归还,那么信号量将自动归还在总值里。
这个时候就要使用redisson提供的另外一个功能,PermitExpirableSemaphore,他提供了为每个信号量设置过期时间的功能。
但是其实阅读一个成熟框架的源码是十分痛苦并且困难的,所以我努力对这个功能里涉及的源码都进行了一些简单的注释。
PermitExpirableSemaphore几个需要注意的点。
1.PermitExpirableSemaphore并不想Semaphore一样能直观的看到剩余多少信号量。他通过维护一个zset类型来记录你目前使用的信号量,该zest中的score被设置为过期的时间,并通过判断zset中的score是否过期以及你的PermitExpirableSemaphore对象中剩余的信号量数值进行判断。
2.上一条中提到的zset中的数据并不会随着信号过期而被自动删除,会一直留存中zset中,当新的信号量进来时,会对zset中最早过期的信号量进行替换。
下面的代码是一个简单的示例。有关于tryAcquire方法的,也就是尝试获取信号量。
然后我会一层一层点进源码并添加注释来帮助大家理解。
@Slf4j
@Service
public class RedissonTestServiceImpl implements RedissonTestService{
@Autowired
private RedissonClient redissonClient;
@Override
public void test() {
RPermitExpirableSemaphore test2 = redissonClient.getPermitExpirableSemaphore("test2");
try {
// String acquire = test2.acquire(10, TimeUnit.MILLISECONDS);
String acquire = test2.tryAcquire(0,100,TimeUnit.SECONDS);
System.out.println(acquire);
// Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
点进tryAcquire(0,100,TimeUnit.SECONDS);这个方法中
public interface RPermitExpirableSemaphore extends RExpirable, RPermitExpirableSemaphoreAsync {
String acquire() throws InterruptedException;
String acquire(long var1, TimeUnit var3) throws InterruptedException;
String tryAcquire();
String tryAcquire(long var1, TimeUnit var3) throws InterruptedException;
//进入这一行 var1为等待(自旋)获取信号量的时间 waittime
//var3 为你给这个信号量设置的过期时间 ttl
//var5 时间的单位 例如 TimeUnit.SECONDS
String tryAcquire(long var1, long var3, TimeUnit var5) throws InterruptedException;
boolean tryRelease(String var1);
void release(String var1);
int availablePermits();
boolean trySetPermits(int var1);
void addPermits(int var1);
boolean updateLeaseTime(String var1, long var2, TimeUnit var4);
}
点进去