我有一个spring应用程序,它可以在集群环境中运行。在该环境中,我使用Redis (和Redisson)作为分布式锁服务。
许多锁用于保护某些任务,这些任务一次只能运行一次,或者只能每X秒启动一次。
应用程序还能够在独立模式下运行(没有redis)。
但是,对于这种情况,我需要一个不同的锁服务实现。我认为这非常简单,因为我只需要在本地创建一个带有特定超时的Lock实例(例如,对于“只运行2分钟”)。然而,当我环顾四周时,我找不到Java接口的任何实现,它支持为锁设置一个超时(这样它就可以在那之后自动解锁)。
有这样的东西吗,或者有一种非常简单的方法(就代码行而言)我可以自己实现它,而我只是错过了这个方法?
锁推动应该如何表现:
编辑:一个具体的例子似乎可以帮助我理解我想要的是什么:
.tryAcquireLock("expensiveTaskId", 10, TimeUnit.Minutes)
,如果它得到了锁,就会返回一个布尔值。在分布式设置中,lockService
的实现使用redis (和Redisson库)分布式锁(这已经很好了)!为了在分布式模式和独立模式之间进行非常简单的切换,我只想要一个不依赖任何外部服务的lockService
实现。因此,我只需要一个Lock的实现,它支持超时。这样,我就可以在锁服务中拥有一个ConcurrentHashMap,它将锁ids映射到这些锁实例。
为什么不简单地使用映射将锁ids映射到时间对象:因为我还需要防止其他线程重新锁定(延长由另一个线程获得的锁的生存期)。
发布于 2015-07-23 13:04:57
您的描述有点模棱两可,因为您说的是锁,但实际上您并没有锁定资源(或者没有提供示例)。我觉得你的问题和日程安排有关。
因为您已经使用了Spring,所以可以查看它的调度选项。最近的版本允许您使用@Scheduled注释来触发该注释。@EnableScheduling启动后台任务执行器。您可以将它与Spring配置文件组合起来,以确保只有在传递概要文件(例如作为JVM参数)时,这些配置文件才会生效。
从文档中复制:
package hello;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTasks {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Scheduled(fixedRate = 5000)
public void reportCurrentTime() {
System.out.println("The time is now " + dateFormat.format(new Date()));
}
}
并使:
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class);
}
}
这里有一个快速指南:
弹簧文档
服务代码(您可能希望与枚举器一起使用字符串以提高清晰度):
import org.apache.commons.collections4.map.PassiveExpiringMap;
public class StandAloneLockService {
private Map ordinaryLocks;
private Map expiringLocks;
public StandAloneLockService() {
this.ordinaryLocks = new HashMap<String, Long>();
this.expiringLocks = new PassiveExpiringMap<String, Long>(2L,
TimeUnit.MINUTES);
}
public synchronized boolean accquireLock(String task) {
if (ordinaryLocks.containsKey("task")
|| expiringLocks.containsKey("task")) {
return false;
} else {
return handle("task");
}
}
private boolean handle(String jdk7) {
switch (jdk7) { // logic
}
}
private void releaseLock(String task) {
switch (task) { // logic
}
}
}
发布于 2017-08-08 23:46:28
您可以尝试在ReentrantLock的等待呼叫中放置超时,例如:
public class MessageUtil {
private static final Lock lock = new ReentrantLock();
public enum Conditions {
BAR_INIT(lock.newCondition()),
TEST_DELAY(lock.newCondition());
Condition condition;
private Conditions(Condition condition) {
this.condition = condition;
}
}
public static void await(Conditions condition, int timeout) throws Interrupted Exception {
lock.lock();
condition.condition.await(timeout, TimeUnit.SECONDS);
lock.unlock();
}
public static void signalAll(Conditions condtition) {
lock.lock();
condition.condition.signalAll();
lock.unlock();
}
}
这个实用工具类允许您使用等待方法等待某个条件,比如等待Bar类在测试中完成初始化或等待某个步骤,然后使用signalAll方法结束等待条件并恢复正常操作。
发布于 2015-07-23 12:38:04
对象类中有一个方法:public final void wait(long timeout)
。请参阅http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait(long)
您只能在同步块中调用它。
作为示例(来自javadoc):
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
https://stackoverflow.com/questions/31587391
复制相似问题