ConcurrentHashMap<Long, CopyOnWriteArrayList<Observation>
mostRecentObservationDB = new ConcurrentHashMap<Long,
CopyOnWriteArrayList<Observation>(524288, 0.75f, 32);
这是我的 map 。我试图同时使用多个线程进行读写,但不知何故它总是创建多个键。
long timeInMilliseconds = System.currentTimeMillis();
if (/* the last key older than 10 seconds comparing to the new key*/) {
CopyOnWriteArrayList<Observation> initializingObservation = new CopyOnWriteArrayList<>();
initializingObservation.add(obs);
mostRecentObservationDB.putIfAbsent(timeInMilliseconds, initializingObservation);
} else {
// Update
}
单独线程,通过删除超过 10 秒的键来过滤此 HashMap 。
while (true) {
try {
Thread.sleep(4000);
if(/*Time (key) older than 10 seconds*/) {
mostRecentObservationDB.remove(key);
}
} catch (Exception e) {
}
}
问题在于,删除 key 后,它会在初始化时创建多个 key 。这是我的日志。
key -> 1501779153776, value
key -> 1501779153826, value
key -> 1501779153876, value
key -> 1501779153896, value
我希望在删除操作时将它们存储为一键。这就是它应该被存储的方式。
key -> 1501779153776, value
但是,当我从中读取内容然后通过 remove()
方法删除所有条目时,我希望在读取 map 内容的过程中没有其他线程写入 map 然后删除它们。
这是行为奇怪的代码:
public static void main(String[] args) {
ConcurrentHashMap<Long, String> tenSecondBucket =
new ConcurrentHashMap<Long, String>();
Thread writingThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1);
if(tenSecondBucket.size() > 0) {
// getting last key
long lastKey = 0;
for (long keyValue : tenSecondBucket.keySet()) {
lastKey = keyValue;
}
if(System.currentTimeMillis() - lastKey > 10000) {
tenSecondBucket.put(System.currentTimeMillis(), "secondEntry");
} else {
tenSecondBucket.put(lastKey, "updatedEntry");
}
} else {
tenSecondBucket.put(System.currentTimeMillis(), "newEntry");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
writingThread.start();
Thread removingThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(4000);
if(tenSecondBucket.size() > 0) {
tenSecondBucket.keySet().stream().forEach(key -> {
if(System.currentTimeMillis() - key > 10000) {
tenSecondBucket.remove(key);
}
});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
removingThread.start();
Thread readingThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(4000);
if(tenSecondBucket.size() > 0) {
tenSecondBucket.keySet().stream().forEach(key -> {
System.out.println("testing key which is timestamp " + key);
});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
readingThread.start();
}
最佳答案
问题在于您派生“lastKey”的方式。您似乎需要 map 中存在的最高时间值,并且您假设它将是 tenSecondBucket.keySet()
的最后一个条目。但是,keySet()
方法返回一个 Set,它本质上是不排序的(在任何情况下,映射都不维护键的有序列表)
所以你需要替换这段代码-
long lastKey = 0;
for (long keyValue : tenSecondBucket.keySet()) {
lastKey = keyValue;
}
使用此代码 -
long lastKey = 0;
for (long keyValue : tenSecondBucket.keySet()) {
lastKey = keyValue > lastKey? keyValue : lastKey;
}
更改后,代码可以正常工作
请注意,代码仍然有改进/重构的空间
关于java - 多个线程尝试以毫秒为键进行写入,但在 ConcurrentHashMap 中创建的不是一个键,而是许多键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45490005/