文章点击量 高并发 java

每次收到点击请求,将文章id放进一个队列里,然后开启一个轮询服务,隔五秒去update到数据库中。每次查询到的文章点击量,有可能是未及时更新的(时效性要求不高)。

使用ConcurrentLinkedQueue  作为队列,因为它线程安全, 长度足够满足需要

public class CargroupService implements ICargroupService {
	private final static Log log = LogFactory.getLog(CargroupService.class);
	/** 文章访问队列 **/
	public static ConcurrentLinkedQueue<String> articleClickQueue = new ConcurrentLinkedQueue<String>();
	/** 定时更新点击量线程 **/
	ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
	/** 更新线程是否启动 **/
	private static volatile boolean isStartScheduled = false;

	  
	@Override
	public void getArticleDetail(ArticleQuery query) {
	  
			
			// 利用线程安全的队列来保存被点击的文章,然后定时更新数据库
			String queueStr = dbInfo.getId()+";"+ip;
			articleClickQueue.offer(queueStr);
			if (isStartScheduled == false) {
				log.debug("初始化文章点击量线程");
				synchronized (CargroupService.class) {
					if (isStartScheduled == false) {
						isStartScheduled = true;
						ArticleClickThread thread = new ArticleClickThread(articleService, labelInfoService);
						scheduledExecutorService.scheduleAtFixedRate(thread, 0, CommonPropertiesConstants.COLLECT_CLICKNUM_SENONDS, TimeUnit.SECONDS);
					}
				}

			}

		}
	 
 

 
}

保存线程代码

public class ArticleClickThread implements Runnable {
	private final static Log log = LogFactory.getLog(ArticleClickThread.class);
 

 

	@Override
	public void run() {
	List<Map<String, Integer>> updateList = new ArrayList<Map<String, Integer>>();
		Map<Integer, Integer> map = new HashMap<Integer, Integer>();
		while (!CargroupService.articleClickQueue.isEmpty()) {
			String articleIdAndIp = CargroupService.articleClickQueue.poll();
			String[] strs = StringUtils.split(articleIdAndIp, ";");
			Integer id = Integer.parseInt(strs[0]);
			String ip = strs[1];
			String articleIdAndIpRedisKey = RpcToolUtils.getArticleIdAndIpRedisKey(String.valueOf(id), ip);
			boolean exit = false;
			try {
				exit = RedisDataSource.existsObject(articleIdAndIpRedisKey);
			} catch (Exception e) {
				log.error("Redis服务挂了---------- !" + e);
				exit = false;
				e.printStackTrace();
			}
			if (exit == false) {
				try {
					// 把该ip访问的文章记录,1天内重新点击或者刷新,不计数
					RedisDataSource.setObject(articleIdAndIpRedisKey, "1", 24*60*60);
				} catch (Exception e) {
					e.printStackTrace();
				}
				if (!map.containsKey(id)) {
					map.put(id, 1);
				} else {
					map.put(id, map.get(id) + 1);
				}
			}
		}
		for (Integer idKey : map.keySet()) {
			Map<String, Integer> paramMap = new HashMap<String, Integer>();
			paramMap.put("articleId", idKey);
			paramMap.put("clickTimes", map.get(idKey));
			updateList.add(paramMap);
		}
		if (updateList != null && updateList.size() > 0) {
			articleService.batchUpdateClickNum(updateList);
			labelInfoService.batchUpdateClickNum(updateList);
		}
		log.debug("完成轮询任务:保存文章点击量");


}

 

第一次启动线程后,每次点击文章只需 往队列里扔文章id,等待被轮询线程保存到数据库。

转载于:https://my.oschina.net/u/1423640/blog/798831

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值