JAVA多线程计数器的问题

本文探讨了在单节点多线程环境下实现计数器的不同方法,包括使用AtomicInteger与volatile变量配合synchronized关键字的方式,并通过具体示例对比了两者的性能表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现在web程序的计数器的应用场景比较多,分布式计数器可以使用redis,但是作为java程序员就会考虑怎么使用单节点多线程实现一个计数器。

 

计数器有两个层次的要求

1,多个线程访问不会造成计数器数值丢失

2,是否对计数器返回的值有要求,比如打印,比如用这个值做些事情

 

如果要满足2的话,那只有一种方式就是加锁,把相应的代码块加锁

 

如果要满足1的话,有两种思路,一个使用Java的并发包里面的atomic类型,一种是使用volatile变量然后使用sychronized变量。

因此有了如下两个程序

程序1

 

package com.fb.concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

public class MutiThreadCount implements Callable<Long> {

	private AtomicInteger ai = new AtomicInteger();

	public MutiThreadCount() {
	}

	@Override
	public Long call() {
		Long start = System.currentTimeMillis();
		for (int i = 0; i < 100000; i++) {
			ai.incrementAndGet();
		}
		Long end = System.currentTimeMillis();
		return end - start;

	}

	public static void main(String[] args) throws InterruptedException,
			ExecutionException {
		ExecutorService es = Executors.newFixedThreadPool(1000);
		Long maxtime = 0l;
		MutiThreadCount mtc = new MutiThreadCount();
		List<Future<Long>> result = new ArrayList<Future<Long>>();
		for (int i = 0; i < 1000; i++) {
			Future<Long> time = es.submit(mtc);
			result.add(time);
		}

		es.shutdown();

		for (Future<Long> f : result) {
			Long time = f.get();
			if (time > maxtime) {
				maxtime = time;
			}
		}
		System.out.println(maxtime);
		System.out.println(mtc.ai.get());
	}

}

 

 

程序2:

 

package com.fb.concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MutiThread1Count implements Callable<Long> {

	private int counting;

	@Override
	public Long call() {
		Long start = System.currentTimeMillis();
		for (int i = 0; i < 100000; i++) {
			incr();
		}
		Long end = System.currentTimeMillis();
		return end - start;

	}

	public synchronized void incr() {
		counting++;
	}

	public static void main(String[] args) throws InterruptedException,
			ExecutionException {
		Long start = System.currentTimeMillis();
		ExecutorService es = Executors.newFixedThreadPool(1000);

		MutiThread1Count mtc1 = new MutiThread1Count();
		List<Future<Long>> result = new ArrayList<Future<Long>>();
		for (int i = 0; i < 1000; i++) {
			Future<Long> time = es.submit(mtc1);
			result.add(time);
		}

		es.shutdown();
		Long maxtime = 0l;
		Long total = 0l;
		for (Future<Long> f : result) {
			Long time = f.get();
			if (time > maxtime) {
				maxtime = time;
			}
			total += time;
		}
		System.out.println("avg time is :" + total / result.size());
		System.out.println(maxtime);
		System.out.println(mtc1.counting);
		Long end = System.currentTimeMillis();
		System.out.println(end - start);
	}

}

 

 

 

但是,在本机环境(intel I7 4核8线程)执行的时候,第一个程序可以吃到100%的cpu,第二个程序最多使用4个cpu线程,而且还不会到100%。

 

简单的理解就是:第一个程序不阻塞,全线程的跑,第二个线程synchronized会有可能导致每次都会重选进入锁的程序。

 

 

但是还是比较质疑这个想法:volatile变量使用比较脆弱,第二种调用效率按说应该比第一个高,参考:

www.ibm.com/developerworks/cn/java/j-jtp06197.html

 

为什么呢?

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值