包括软件、新闻和话题以及代码在内的信息,用户访问过一次就会给访问次数字段增1。在oschina上这个操作是异步的,访问的时候只是将数据在内存中保存,每隔固定时间将这些数据写入数据库。 有两个注意实现(详看代码中的注释): 1. 当tomcat停止时而且尚未达到运行周期时将剩余数据写回 2. 必须显式关闭数据库连接,因为线程的运行不受Filter控制,无法自动关闭连接,如果不关闭会导致连接泄漏 这个类提供了一个main方法可直接运行,需要用到此类的时候,只需要将自己的写数据库逻辑填充上即可。 具体使用方法请看 main 函数。 [文件] VisitStatService.java ~ 3KB 下载(192)001 | package net.oschina.service; |
004 | import java.util.concurrent.*; |
006 | import org.apache.commons.logging.Log; |
007 | import org.apache.commons.logging.LogFactory; |
012 | * @date 2011-1-6 下午03:49:40 |
014 | public class VisitStatService extends TimerTask { |
016 | private final static Log log = LogFactory.getLog(VisitStatService. class ); |
017 | private static boolean start = false ; |
018 | private static VisitStatService daemon; |
019 | private static Timer click_timer; |
020 | private final static long INTERVAL = 60 * 1000 ; |
025 | private final static byte [] TYPES = new byte []{ |
026 | 0x01 , 0x02 , 0x03 , 0x04 , 0x05 |
030 | private final static ConcurrentHashMap<Byte, ConcurrentHashMap<Long, Integer>> queues = |
031 | new ConcurrentHashMap<Byte, ConcurrentHashMap<Long, Integer>>(){{ |
032 | for ( byte type : TYPES) |
033 | put(type, new ConcurrentHashMap<Long, Integer>()); |
041 | public static void record( byte type, long obj_id) { |
042 | ConcurrentHashMap<Long, Integer> queue = queues.get(type); |
044 | Integer nCount = queue.get(obj_id); |
045 | nCount = (nCount== null )? 1 :nCount+ 1 ; |
046 | queue.put(obj_id, nCount.intValue()); |
047 | System.out.printf( "record (type=%d,id=%d,count=%d)\n" ,type,obj_id,nCount); |
055 | public static void start() { |
057 | daemon = new VisitStatService(); |
058 | click_timer = new Timer( "VisitStatService" , true ); |
059 | click_timer.schedule(daemon, INTERVAL, INTERVAL); |
062 | log.info( "VisitStatService started." ); |
068 | public static void destroy(){ |
070 | click_timer.cancel(); |
073 | log.info( "VisitStatService stopped." ); |
078 | for ( byte type : TYPES){ |
079 | ConcurrentHashMap<Long, Integer> queue = queues.remove(type); |
080 | queues.put(type, new ConcurrentHashMap<Long, Integer>()); |
084 | log.fatal( "Failed to flush click stat data." , t); |
093 | public boolean cancel() { |
094 | boolean b = super .cancel(); |
105 | private void _flush( byte type, ConcurrentHashMap<Long, Integer> queue){ |
111 | System.out.printf( "Flush to database: type=%d\n" , type); |
119 | public static void main(String[] args) throws Exception { |
121 | for ( int i= 0 ;i< 10 ;i++) |
122 | new Timer( "OfferTask_" +(i+ 1 ), false ).schedule( |
124 | private Random rnd = new Random(System.currentTimeMillis()); |
127 | record(TYPES[rnd.nextInt(TYPES.length)],rnd.nextInt( 10 )); |
|