CODE大全
版权声明:本文为博主原创文章,未经博主允许不得转载。

Java实现多线程环境下的计数器功能

发布时间:『 2017-09-26 15:45』  博客类别:编程语言  阅读(88) 评论(0)

我们在做一个Web应用程序会遇到这样一个需求:在全局定义一个count,每次调用一个接口则count+1,用于统计接口调用次数和频率,代码入下:

public class CountServlet implements HttpServlet {
    private long count = 0;
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) 
	throws ServletException, IOException {
        count++;
    }
}

上面这段代码如果在单线程环境没有问题,但是我们知道Servlet是多线程的,如果两个线程同时请求service,当线程1的count+1后,线程2进来了,这个时候count还是0,加1后得到的值还是1,这并不是我们想要的结果。有人会说在方法上面加上syncronized关键词就行了,这样做是没有问题,也能达到我们的要求。但是加上他后,线程1访问service方法后,会开启同步锁,线程2必须要等待线程1执行完成才能进行下一步操作,如果线程1执行太长或者死循环,会导致死锁,也大大影响了我们的程序性能。 

在java1.5后,sun公司推出了java.util.concurrent同步包,我们可以使用这个包下面的一些类库来实现我们的需求,请看代码:

public class CountServlet implements HttpServlet {
    private AtomicLong count = new AtomicLong(0);
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) 
	throws ServletException, IOException {
        count.incrementAndGet();
    }
}

AtomicLong类保证了long类型的原子性,它和syncronized不同的是,他并不是简单加上同步锁,相反,他并不会锁住当前方法。而是利用一种称之为“无锁算法”的方式,而CAS(Compare And Swap)就是非常著名的无锁算法,它的基本原理大致是这样的:它包含3个操作数,内存值V、旧的值A,要修该的新的值B,仅当A和V相同时,将V修改为B,否则什么都不做。 

请看具体的代码实现:

private void compareAndSwap(int v,int a,int b){
	if(v == a){
		v = b;
	}
	return v;
}

在java里面,它是定义的native方法,通过native方法操作机器指令,从而实现数据的原子性。 

但是如果有两个线程同时访问,会不会破坏其原子性,答案是当然不会。 

因为它是由若干条指令构成的,用于完成一项功能,它是连续不断的,在执行过程中不允许被中断。 

以上便是Atomic包下的类库的原理,在实现这类需求的时候就可以考虑通过它去实现,既保证了性能,又保证了原子性。


——— 全文完 ———
如有版权问题,请联系532009913@qq.com。
关键字:   java     多线程     syncronized     AtomicLong  
评论信息
暂无评论
发表评论
验证码: 
Powered by CODE大全 | 鄂ICP备14009759号-2 | 网站留言 Copyright © 2014-2016 CODE大全 版权所有