java – 全局内存计数器,它是线程安全的,并且每x个增量刷新到mys
是否可以创建所有servlet将使用的内存中计数器?
此全局计数器将跟踪Web应用程序的网页浏览量,计数器将特定于当前登录的用户.即,该集合将具有每个用户的密钥. globalCounterMap[userId].incrementCounter += 1; 在某个间隔或网页浏览计数,我想将当前计数保存到mysql(插入一个新行)例如: table_pageviews [id,userId,pageview_count,date] 所以这个计数器将在刷新后重置为0. 因此,如果我有一个所有servlet都将继承的BaseServlet,我该如何定义这个字段? (最后,静态?) ConcurrentHashMap是否合适?也许我可以为每个条目存储一个AtomicLong值. 在刷新期间,我可以通过设置为0来使用原子long的getAndSet,并保存我得到的值:http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/atomic/AtomicLong.html 在刷新到mysql进程期间是否必须同步? (假设我每1K页面浏览量这样做) 更新 因此,即使我有10个服务器,每个服务器都有自己的内存计数器,事情仍然有效,因为它们最终都会将它们的计数刷新到数据库,然后我将简单地聚合行以获得最终计数. 解决方法
康斯坦丁说,像redis这样的东西可能是更好的解决方案. Cassandra专柜也是做这类事情的好方法.
如果你想用java做这个,这里有一些代码可以安全地增加计数而不会阻塞, class Counter { private final ConcurrentHashMap<String,AtomicInteger> counts = new ConcurrentHashMap<String,AtomicInteger>(); //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<String,Integer> toFlush = new HashMap<String,Integer>(); for(Map.Entry<String,AtomicInteger> 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<String,Integer> clearedEntry : toFlush.entrySet()) { writeToDb(clearedEntry.getKey(),clearedEntry.getValue()); } } public void writeToDb(String user,int count) { //do something with the count here } } 代码相当复杂,正如Peter Lawrey所说,使用synchronized关键字保护的简单映射可能性能足够好并且更易于维护. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |