
org.redisson.RedissonCountDownLatch Maven / Gradle / Ivy
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.redisson.api.RCountDownLatch;
import org.redisson.api.RFuture;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.pubsub.CountDownLatchPubSub;
/**
* Distributed alternative to the {@link java.util.concurrent.CountDownLatch}
*
* It has a advantage over {@link java.util.concurrent.CountDownLatch} --
* count can be reset via {@link #trySetCount}.
*
* @author Nikita Koksharov
*
*/
public class RedissonCountDownLatch extends RedissonObject implements RCountDownLatch {
public static final Long zeroCountMessage = 0L;
public static final Long newCountMessage = 1L;
private static final CountDownLatchPubSub PUBSUB = new CountDownLatchPubSub();
private final UUID id;
protected RedissonCountDownLatch(CommandAsyncExecutor commandExecutor, String name, UUID id) {
super(commandExecutor, name);
this.id = id;
}
public void await() throws InterruptedException {
RFuture future = subscribe();
try {
commandExecutor.syncSubscription(future);
while (getCount() > 0) {
// waiting for open state
RedissonCountDownLatchEntry entry = getEntry();
if (entry != null) {
entry.getLatch().await();
}
}
} finally {
unsubscribe(future);
}
}
@Override
public boolean await(long time, TimeUnit unit) throws InterruptedException {
long remainTime = unit.toMillis(time);
long current = System.currentTimeMillis();
RFuture promise = subscribe();
if (!await(promise, time, unit)) {
return false;
}
try {
remainTime -= (System.currentTimeMillis() - current);
if (remainTime <= 0) {
return false;
}
while (getCount() > 0) {
if (remainTime <= 0) {
return false;
}
current = System.currentTimeMillis();
// waiting for open state
RedissonCountDownLatchEntry entry = getEntry();
if (entry != null) {
entry.getLatch().await(remainTime, TimeUnit.MILLISECONDS);
}
remainTime -= (System.currentTimeMillis() - current);
}
return true;
} finally {
unsubscribe(promise);
}
}
private RedissonCountDownLatchEntry getEntry() {
return PUBSUB.getEntry(getEntryName());
}
private RFuture subscribe() {
return PUBSUB.subscribe(getEntryName(), getChannelName(), commandExecutor.getConnectionManager());
}
private void unsubscribe(RFuture future) {
PUBSUB.unsubscribe(future.getNow(), getEntryName(), getChannelName(), commandExecutor.getConnectionManager());
}
@Override
public void countDown() {
get(countDownAsync());
}
@Override
public RFuture countDownAsync() {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local v = redis.call('decr', KEYS[1]);" +
"if v <= 0 then redis.call('del', KEYS[1]) end;" +
"if v == 0 then redis.call('publish', KEYS[2], ARGV[1]) end;",
Arrays.
© 2015 - 2025 Weber Informatics LLC | Privacy Policy