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

我们在做一个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包下的类库的原理,在实现这类需求的时候就可以考虑通过它去实现,既保证了性能,又保证了原子性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lynnlovemin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值