加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 全局内存计数器,它是线程安全的,并且每x个增量刷新到mys

发布时间:2020-12-15 08:46:06 所属栏目:Java 来源:网络整理
导读:是否可以创建所有servlet将使用的内存中计数器? 此全局计数器将跟踪Web应用程序的网页浏览量,计数器将特定于当前登录的用户.即,该集合将具有每个用户的密钥. globalCounterMap[userId].incrementCounter += 1; 在某个间隔或网页浏览计数,我想将当前计数保存
是否可以创建所有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关键字保护的简单映射可能性能足够好并且更易于维护.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读