`
raymond.chen
  • 浏览: 1437449 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

支持多线程并发的计数器实现

 
阅读更多

        该计数器支持多个客户端线程并发访问,计数器的key/value存储在一个静态型的AtomicLongMap对象中,另外有一个守护线程定期将计数器的数据取出,然后存储到数据库、文件等地方。该范例可以做适当的调整,然后应用到统计页面访问量、菜单点击量、IP访问量等计数的场景。下面是计数器的源码:

public class PageViewsStatistics {
	private static PageViewsStatistics pvStat = null;
	private static ScheduledExecutorService service = null;
	private static AtomicLongMap<String> pvCounterMap = AtomicLongMap.create(); //线程安全,支持并发
	private static ReentrantLock lock = new ReentrantLock(); //锁
	private static int MONITOR_INITIAL_DELAY_SECONDS = 3; //监控初始延迟秒数
	private static int MONITOR_INTERVAL_SECONDS = 10; //监控间隔秒数
	private static Map<String, Long> map2 = new HashMap<String, Long>();
	
	/**
	 * 计数值增加1
	 * @param key
	 */
	public long incr(String key){
		long result = -1;
		while(true){
			if(!lock.isLocked()){ //在做pop动作时,不能进行计数,等待直到完成pop动作
				result = pvCounterMap.incrementAndGet(key);
				break;
			}else{
				try {
					TimeUnit.MILLISECONDS.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		return result;
	}
	
	/**
	 * 获取单实例对象
	 * @return
	 */
	public static PageViewsStatistics newInstance(){
		if(pvStat == null){
			synchronized (PageViewsStatistics.class) {
				if(pvStat == null){
					pvStat = new PageViewsStatistics();
				}
			}
		}
		return pvStat;
	}

	/**
	 * 构造函数
	 */
	public PageViewsStatistics(){
		createExecutorService();
		startMonitor();
	}
	
	/**
	 * 创建计划任务线程池
	 */
	private void createExecutorService() {
		if(service == null){
			service = Executors.newScheduledThreadPool(1, new ThreadFactory() {
				@Override
				public Thread newThread(Runnable r) {
					Thread thread = new Thread(r);
					thread.setDaemon(true); //宿主线程
					return thread;
				}
			});
		}
	}
	
	/**
	 * 开始监控计数器
	 */
	private void startMonitor(){
//表示在上一个任务结束执行之后,延迟多少秒之后再执行,是从上一个任务结束时开始计算
		service.scheduleWithFixedDelay(
				new StatMonitorRunner(), 
				MONITOR_INITIAL_DELAY_SECONDS, 
				MONITOR_INTERVAL_SECONDS, 
				TimeUnit.SECONDS);
	}
	
	/**
	 * 获取访问量计数器中的访问量累计值,放到一个临时Map中,然后清空访问量计数器
	 * @return
	 */
	private Map<String, Long> popCounter(){
		Map<String, Long> newMap = new HashMap<String, Long>();
		lock.lock();
		try{
			for(Iterator<String> it = pvCounterMap.asMap().keySet().iterator(); it.hasNext(); ){
				String key = it.next();
				newMap.put(key, pvCounterMap.get(key));
			}
			pvCounterMap.clear();
		}finally{
			lock.unlock();
		}
		return newMap;
	}
	
	class StatMonitorRunner implements Runnable{
		@Override
		public void run() {
			Map<String, Long> map = popCounter();
			
			//可以将计数值写到数据库中
			for(Iterator<String> it = map.keySet().iterator(); it.hasNext(); ){
				String key = it.next();
				if(map2.containsKey(key)){
					map2.put(key, new Long(map2.get(key).longValue() + map.get(key).longValue()));
				}else{
					map2.put(key, map.get(key));
				}
			}
			System.out.println(map2);
		}
	}
}

 

下面是测试代码:

public class AtomicLongMapTest {
	public static void main(String[] args) {
		ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
		for(int i=0; i<4; i++){
			AtomicLongMapTest t = new AtomicLongMapTest();
			service.scheduleWithFixedDelay(t.new MyRunner("name"), 0, 1000, TimeUnit.MILLISECONDS);
		}
	}
	
	class MyRunner implements Runnable{
		private String name;
		public MyRunner(String name){
			this.name = name;
		}
		
		@Override
		public void run() {
			long l = PageViewsStatistics.newInstance().incr(this.name);
			System.out.println(this.name + " > " + l);
		}
	}
}

 

分享到:
评论

相关推荐

    java 多线程并发实例

    在Java编程中,多线程并发是提升程序执行效率、充分利用多核处理器资源的重要手段。本文将基于"java 多线程并发实例"这个主题,深入探讨Java中的多线程并发概念及其应用。 首先,我们要了解Java中的线程。线程是...

    Java 模拟线程并发

    最后,Java并发库还包含了很多其他有用的工具,如Semaphore(信号量)用于控制同时访问特定资源的线程数量,CyclicBarrier(循环屏障)和CountDownLatch(计数器门锁)用于多线程间的协作,以及Lock接口及其实现如...

    多线程,高并发.zip

    在IT领域,多线程和高并发是两个关键概念,特别是在Java编程中,它们对于构建高效、可扩展的系统至关重要。下面将详细解释这两个概念及其在Java中的实现和应用。 多线程是指在一个应用程序中同时运行多个独立的执行...

    bcb6多线程计数器

    在编程领域,多线程是实现并发执行任务的重要手段,特别是在C++ Builder 6 (bcb6) 这样的环境中。本示例着重探讨如何在多线程环境下正确实现一个计数器,以避免线程安全问题。我们将讨论两种方法:一种可能会导致...

    java多线程代码行数计数器

    Java多线程代码行数计数器是一款实用的工具,主要功能是针对特定后缀名的文件进行代码行数的统计。在软件工程中,了解代码行数有时可以帮助开发者评估项目规模,跟踪代码增长,或者在性能优化时作为参考。这款工具...

    Java多线程并发实战

    ### Java多线程并发实战知识点解析 #### 一、引言 在计算机科学领域,**多线程**和**并发**技术是现代软件开发中不可或缺的一部分。随着处理器核心数量的增加,利用多线程和并发可以显著提高应用程序的性能和响应...

    memcache实现网站全局计数器

    通过这种方式,可以保证在多线程环境下,对同一个计数器的并发操作不会导致数据错误。 2. **锁机制**:另一种方法是引入锁机制。当一个客户端开始操作计数器时,获取该键的锁,完成操作后再释放。这样可以确保在...

    多线程并发处理

    在计算机科学中,多线程并发处理是一种编程技术,它允许多个线程在同一时间执行,从而提升程序的效率和响应速度。...具体实现将取决于代码细节,但这些基础知识点提供了一个理解多线程并发处理的起点。

    Servlet线程同步计数器实验

    Servlet线程同步计数器实验是Java Web开发中一个重要的实践课题,主要涉及到Servlet容器如何处理并发请求以及如何确保在多线程环境下的数据一致性。在这个实验中,我们将深入理解Servlet生命周期、线程模型以及线程...

    Java多线程并发执行demo代码实例

    "Java多线程并发执行demo代码实例" ...通过这个demo代码实例,我们学习了Java多线程并发执行的实现,包括泛型、线程池、阻塞队列和计数器等概念。这些概念可以帮助开发者编写更加高效、灵活和可重用的代码。

    java多线程并发编程例子

    Java多线程并发编程是Java开发中的重要领域,特别是在服务器端和高并发应用中不可或缺。`java.util.concurrent`包提供了丰富的工具类,帮助开发者更好地管理线程和优化并发性能。以下将详细介绍标题和描述中涉及的...

    多线程单例模式并发访问

    ### 多线程单例模式并发访问 #### 一、多线程基础概念 在讨论多线程单例模式及并发访问之前,我们先来了解一些基本概念。 **进程**和**线程**是计算机科学中的两个核心概念,它们之间的关系紧密而复杂。 - **进程...

    vb多线程控件能实现简单的多线程

    为了克服这些限制,开发者可以考虑升级到更新的.NET框架,如VB.NET,它提供了更强大的多线程支持和更好的线程管理机制。此外,学习和理解线程同步、并发编程原则以及线程池等概念,也是提升VB多线程应用质量的关键。

    多线程与高并发-电子.pdf

    多线程与高并发是计算机科学中非常重要的两个概念,它们在提高软件程序的性能、响应速度和资源利用率方面起着至关重要的作用。在当今的互联网时代,特别是在产业互联网和5G技术的推动下,多线程和高并发的应用变得...

    线程并发拷贝程序

    综上所述,这个“线程并发拷贝程序”不仅展示了如何在Linux环境下利用多线程技术进行文件的并发处理,还深入探讨了线程同步、内存管理以及系统调用等多个重要的计算机科学概念。这对于理解操作系统原理、提高编程...

    用 setjmp 和 longjmp 实现多线程(1)_多线程_

    在C语言中,setjmp和longjmp是两个与异常处理和非局部跳转相关的函数,它们可以被用来实现一种特殊的多线程效果。虽然这两个函数并非设计为创建和管理线程的标准方法,但在某些特定场景下,它们可以模拟多线程的行为...

    Python并发:多线程与多进程的详解

    3.多线程并发下载图片 4.多进程并发提高数字运算 关于并发 在计算机编程领域,并发编程是一个很常见的名词和功能了,其实并发这个理念,最初是源于铁路和电报的早期工作。比如在同一个铁路系统上如何安排多列火车,...

    Redis实现高并发计数器

    本文将详细讨论如何利用Redis这一高性能的内存数据存储系统来实现高并发计数器,并以一个接口一天限制调用次数为例进行说明。 Redis是一个开源的键值存储系统,它支持多种数据结构,如字符串、哈希、列表、集合、...

    大漠多线程模板_大漠_大漠多线程_

    在C#中,`System.Threading`命名空间提供了大量的类和方法来支持多线程编程,如`Thread`、`ThreadPool`、`Task`等。大漠的模板可能整合了这些工具,并进行了封装,使得开发者可以更方便地创建、管理和同步线程。 ...

    Java多线程端口快速扫描

    - `CountDownLatch`:计数器,常用于多线程同步,例如,所有线程都完成任务后才能继续执行后续操作。 - `CyclicBarrier`:循环栅栏,允许一组线程等待其他线程到达某个点,然后一起继续执行。 4. **TCP连接与套接...

Global site tag (gtag.js) - Google Analytics