目录
5.tryAcquire(long waitTime, TimeUnit unit)
6.tryAcquire(int permits, long waitTime, TimeUnit unit)
11.trySetPermits(int permits)
一.简介
RSemaphore基于 Redis 的Semaphore开发。使用RSemaphore获取资源的顺序是不可预测的,所以它是一种非公平锁。可以理解为分布式的信号量,它的作用是用来限制同时访问共享区域的线程数量。
二.方法总结
Modifier and Type | Method | Description |
---|---|---|
void | acquire() | 获取1个permit . |
void | acquire(int permits) | 获取定义数量的permits . |
void | addPermits(int permits) | 按定义的值增加或减少可用许可证的数量。 |
int | availablePermits() | 返回可用许可证的数量。 |
int | drainPermits() | 获取并返回所有立即可用的许可证。 |
void | release() | 释放1个permit . |
void | release(int permits) | 释放定义数量的permits . |
boolean | tryAcquire() | 尝试获取当前可用的许可证。 |
boolean | tryAcquire(int permits) | 尝试获取定义数量的permits 。 |
boolean | tryAcquire(int permits, long waitTime, TimeUnit unit) | 尝试获取定义数量的permits 。如果获取不到,就一直等待,直到获取到指定数量的permits 。最长等待waitTime时间。 |
boolean | tryAcquire(long waitTime, TimeUnit unit) | 尝试获取1个permit 。如果获取不到,就一直等待,直到成功获取1个permit 。最长等待waitTime时间。 |
boolean | trySetPermits(int permits) | 尝试设置许可证数量。 |
三.方法详情
1.acquire()
void acquire() throws InterruptedException
获取1个permit
。如果没有,会一直等待,直到获得1个permit
。
抛出:
InterruptedException
- 如果当前线程被中断
2.acquire(int permits)
void acquire(int permits) throws InterruptedException
获取定义数量的permits。如果没有,会一直等待,直到获得定义数量的permit
s。
参数:
permits
- 获得许可的数量
抛出:
InterruptedException
- 如果当前线程被中断
IllegalArgumentException
- 如果permits
是负数
3.tryAcquire()
boolean tryAcquire()
尝试获取当前可用的许可证。
false
4.tryAcquire(int permits)
boolean tryAcquire(int permits)
尝试获取定义数量的permits
。
参数:
permits
- 获得许可的数量
返回:
如果成功获得指定数量的许可证,返回true;否则返回false
5.tryAcquire(long waitTime, TimeUnit unit)
boolean tryAcquire(long waitTime, TimeUnit unit) throws InterruptedException
尝试获取1个permit
。如果获取不到,就一直等待,直到成功获取1个permit
。最长等待waitTime时间。
参数:
waitTime
- 最长等待时间
unit
- 时间单位
返回:
如果成功获得1个permit,返回true;否则返回false
抛出:
InterruptedException
- 如果当前线程被中断
6.tryAcquire(int permits, long waitTime, TimeUnit unit)
boolean tryAcquire(int permits, long waitTime, TimeUnit unit) throws InterruptedException
尝试获取定义数量的permits
。如果获取不到,就一直等待,直到获取到指定数量的permits
。最长等待waitTime时间。
参数:
permits
- 许可证数量
waitTime
- 最长等待时间
unit
- 时间单位
返回:
如果成功获得指定数量的许可证,返回true;否则返回false
抛出:
InterruptedException
- 如果当前线程被中断
7.release()
void release()
释放1个permit
。增加一个可用permit的数量。
8.release(int permits)
void release(int permits)
释放定义数量的permits
。增加定义数量个的可用permit的数量。
9.availablePermits()
int availablePermits()
返回可用许可证的数量。
10.drainPermits()
int drainPermits()
获取并返回所有立即可用的许可证。
11.trySetPermits(int permits)
boolean trySetPermits(int permits)
尝试设置许可数量。
返回:
如果许可证数量设置成功返回true
;如果许可证数量已经设置过,返回false
。
12.addPermits(int permits)
void addPermits (int permit)
四.使用示例
//可以在使用前初始化,但它不是必需的
RSemaphore semaphore = redisson.getSemaphore("semaphore");
// 同时最多允许3个线程获取锁
semaphore.trySetPermits(3);
for(int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]尝试获取Semaphore锁");
semaphore.acquire();
System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]成功获取到了Semaphore锁,开始工作");
Thread.sleep(3000);
semaphore.release();
System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]释放Semaphore锁");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
五.源码解析
1.semaphore.trySetPermits(3);
public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
@Override
public boolean trySetPermits(int permits) {
return get(trySetPermitsAsync(permits));
}
@Override
public RFuture<Boolean> trySetPermitsAsync(int permits) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local value = redis.call('get', KEYS[1]); " +
"if (value == false or value == 0) then "
+ "redis.call('set', KEYS[1], ARGV[1]); "
+ "redis.call('publish', KEYS[2], ARGV[1]); "
+ "return 1;"
+ "end;"
+ "return 0;",
Arrays.<Object>asList(getName(), getChannelName()), permits);
}
}
执行流程为:
- get semaphore,获取到semaphore信号量的当前的值
- 第一次数据为0, 然后使用set semaphore 3,将这个信号量同时能够允许获取锁的客户端的数量设置为3。(注意到,如果之前设置过了信号量,将无法再次设置,直接返回0。想要更改信号量总数可以使用addPermits方法)
- 然后redis发布一些消息,返回1
2.semaphore.acquire()
public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
@Override
public void acquire(int permits) throws InterruptedException {
if (tryAcquire(permits)) {
return;
}
RFuture<RedissonLockEntry> future = subscribe();
commandExecutor.syncSubscription(future);
try {
while (true) {
if (tryAcquire(permits)) {
return;
}
getEntry().getLatch().acquire(permits);
}
} finally {
unsubscribe(future);
}
// get(acquireAsync(permits));
}
@Override
public boolean tryAcquire(int permits) {
return get(tryAcquireAsync(permits));
}
@Override
public RFuture<Boolean> tryAcquireAsync() {
return tryAcquireAsync(1);
}
@Override
public RFuture<Boolean> tryAcquireAsync(int permits) {
if (permits < 0) {
throw new IllegalArgumentException("Permits amount can't be negative");
}
if (permits == 0) {
return RedissonPromise.newSucceededFuture(true);
}
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local value = redis.call('get', KEYS[1]); " +
"if (value ~= false and tonumber(value) >= tonumber(ARGV[1])) then " +
"local val = redis.call('decrby', KEYS[1], ARGV[1]); " +
"return 1; " +
"end; " +
"return 0;",
Collections.<Object>singletonList(getName()), permits);
}
}
执行流程为:
- get semaphore,获取到一个当前的值,比如说是3,3 > 1
- decrby semaphore 1,将信号量允许获取锁的客户端的数量递减1,变成2
- decrby semaphore 1
- decrby semaphore 1
- 执行3次加锁后,semaphore值为0
此时如果再来进行加锁则直接返回0,然后进入死循环去获取锁
3.semaphore.release()
public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
@Override
public void release(int permits) {
get(releaseAsync(permits));
}
@Override
public RFuture<Void> releaseAsync() {
return releaseAsync(1);
}
@Override
public RFuture<Void> releaseAsync(int permits) {
if (permits < 0) {
throw new IllegalArgumentException("Permits amount can't be negative");
}
if (permits == 0) {
return RedissonPromise.newSucceededFuture(null);
}
return commandExecutor.evalWriteAsync(getName(), StringCodec.INSTANCE, RedisCommands.EVAL_VOID,
"local value = redis.call('incrby', KEYS[1], ARGV[1]); " +
"redis.call('publish', KEYS[2], value); ",
Arrays.<Object>asList(getName(), getChannelName()), permits);
}
}
release semaphore 1,每次一个客户端释放掉这个锁的话,就会将信号量的值累加1,信号量的值就不是0了。
总结
这个组件还是比较简单的,实现了分布式信号量锁。
附上github链接:分布式锁和同步器