康斯坦丁说,像redis这样的东西可能是更好的解决方案. Cassandra专柜也是做这类事情的好方法.
如果你想用java做这个,这里有一些代码可以安全地增加计数而不会阻塞,
class Counter {
private final ConcurrentHashMap counts = new ConcurrentHashMap();
//increment the count for the user
public void increment(String user) {
while(true) {
AtomicInteger current = counts.get(user);
if(current == null) {
//new user, initialize the count
counts.putIfAbsent(user, new AtomicInteger());
continue;
}
int value = current.incrementAndGet();
if(value > 0) {
//we have incremented the counter
break;
} else {
//someone is flushing this key, remove it
//so we can increment on our next iteration
counts.replace(user, current, new AtomicInteger());
}
}
}
//call this periodically to flush keys to the database
//this will empty the counts map so that users who
//are not active do not take up space
public void flush() {
Map toFlush = new HashMap();
for(Map.Entry entry : counts.entrySet()) {
String user = entry.getKey();
AtomicInteger currentCount = entry.getValue();
//stop incrementing this count
counts.remove(user, currentCount);
//if someone is trying to increment this AtomicInteger after
//we remove it, they will see a -ve value from incrementAndGet, and
//will know their increment did not succeed
Integer count = currentCount.getAndSet(Integer.MIN_VALUE);
toFlush.put(user, count);
}
for(Map.Entry clearedEntry : toFlush.entrySet()) {
writeToDb(clearedEntry.getKey(), clearedEntry.getValue());
}
}
public void writeToDb(String user, int count) {
//do something with the count here
}
}
代码相当复杂,正如Peter Lawrey所说,使用synchronized关键字保护的简单映射可能性能足够好并且更易于维护.