我正在寻找具有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”并将值设置为到期时间,然后每秒运行一个线程并删除其值(到期时间)已经过去的所有元素,但是我不确定那会有多高效?难道没有一个更简单的解决方案吗?
答案 0 :(得分:4)
http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/cache/CacheBuilder.html#expireAfterWrite(long, java.util.concurrent.TimeUnit) - guava库包含这样的缓存。
答案 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);
}
即使重新启动应用程序,也不会重复此操作。
注意:它会在以下后重复:
答案 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;
}
}
}