具有到期可能性的简单Java字符串缓存

时间:2011-09-21 13:20:40

标签: java concurrency set

我正在寻找具有Java 1.5应用程序的过期功能的并发Set。它将用作存储/缓存在一定时间后过期的名称(即字符串值)的简单方法。

我试图解决的问题是两个线程不能在一定时间内使用相同的名称值(所以这是一个黑名单,确保相同的“名称”,这就像一条消息引用,在某个时间段过去之前不能被另一个线程重用。我自己不控制名称生成,因此我无法对实际的名称/字符串执行唯一性,它应该被视为一种限制/限制机制,以防止同一名称每秒使用超过一次。 / p>

实施例: 线程#1执行cache.add("unique_string, 1),其存储名称“unique_string”1秒。 如果任何线程通过例如寻找“unique_string” {1}在1秒内它会得到肯定的回复(项目存在),但之后该项目应该过期并从集合中删除。

容器有时会每秒处理50-100次插入/读取。

我一直在寻找不同的解决方案,但我找不到任何我认为真正符合我需求的东西。这感觉就像一个简单的问题,但我发现的所有解决方案都过于复杂或过度。

一个简单的想法是将一个cache.get("unique_string")对象的密钥设置为“name”并将值设置为到期时间,然后每秒运行一个线程并删除其值(到期时间)已经过去的所有元素,但是我不确定那会有多高效?难道没有一个更简单的解决方案吗?

5 个答案:

答案 0 :(得分:4)

答案 1 :(得分:3)

如何使用线程执行器

创建项目到期的Map
//Declare your Map and executor service
final Map<String, ScheduledFuture<String>> cacheNames = new HashMap<String, ScheduledFuture<String>>();
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

然后,您可以使用一种方法将缓存名称添加到您的集合中,该名称将在过期后将其删除,在此示例中为一秒。我知道这似乎是相当多的代码,但它只是在几种方法中可以是一个非常优雅的解决方案。

ScheduledFuture<String> task = executorService.schedule(new Callable<String>() {
  @Override
  public String call() {
    cacheNames.remove("unique_string");
    return "unique_string";
  }
}, 1, TimeUnit.SECONDS);
cacheNames.put("unique_string", task);

答案 2 :(得分:0)

一个不重复的简单唯一字符串模式

private static final AtomicLong COUNTER = new AtomicLong(System.currentTimeMillis()*1000);
public static String generateId() {
     return Long.toString(COUNTER.getAndIncrement(), 36);
}

即使重新启动应用程序,也不会重复此操作。

注意:它会在以下后重复:

  • 你重启,你每秒产生的ids数超过一百万。
  • 293年后。如果时间不够长,你可以减少1000到100,并获得2930年。

答案 3 :(得分:0)

取决于 - 如果你需要严格的时间条件,或软(如1秒+/- 20ms)。 此外,如果您需要离散缓存失效或“按顺序”。

对于严格的条件,我建议添加一个不同的线程,每隔20毫秒就会使缓存无效。

此外,您可以在存储的密钥时间戳内部检查它是否已过期。

答案 4 :(得分:0)

为什么不存储密钥在地图中列入黑名单的时间(如Konoplianko所示)?

这样的事情:

private final Map<String, Long> _blacklist = new LinkedHashMap<String, Long>() {
   @Override
   protected boolean removeEldestEntry(Map.Entry<String, Long> eldest) {
      return size() > 1000;
   }
};

public boolean isBlacklisted(String key, long timeoutMs) {
   synchronized (_blacklist) {
      long now = System.currentTimeMillis();
      Long blacklistUntil = _blacklist.get(key);
      if (blacklistUntil != null && blacklistUntil >= now) {
         // still blacklisted
         return true;
      } else {
         // not blacklisted, or blacklisting has expired 
         _blacklist.put(key, now + timeoutMs);
         return false;
      }
   }
}
相关问题