`
荧火流年
  • 浏览: 60727 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

AtomicInteger在实际项目中的应用

    博客分类:
  • java
 
阅读更多

今天写代码,尝试使用了AtomicInteger这个类,感觉使用起来很爽,特别适用于高并发访问,下面贴一个简单的例子:

CashierContext类部分代码:

private Map<String, AtomicInteger> counter          = new HashMap<String, AtomicInteger>();


private void initCounter() {
     counter.put("cvm", new AtomicInteger(0));
}

//被调用一次自动+1

public MobileCashierViewModel getCvm() {

        if (cvm != null) {
            counter.get("cvm").incrementAndGet();
        }
        return cvm;
    }
 

使用场景:

因为通过WS服务获取MobileCashierViewModel 这个对象比较频繁,会很影响系统资源,可以将cvm存入缓存中,想要查看缓存cvm有多大价值,那么可以设置一个计数,来统记cvm被调用的次数

 

 

然后将CashierContext放入ThreadLocal中,然后再写一个过滤器,在过滤器里面可以得到获取这个服务从缓存中取的次数,这个就可以很容易看出来缓存价值。

 

那么为什么不使用记数器自加呢,例如count++这样的,因为这种计数是线程不安全的,高并发访问时统计会有误,而AtomicInteger为什么能够达到多而不乱,处理高并发应付自如呢,我们才看看AtomicInteger的源代码:

 

 

   private volatile int value;
 

 

大家可以看到有这个变量,value就是你设置的自加起始值。注意看它的访问控制符,是volatile,这个就是保证AtomicInteger线程安全的根源,熟悉并发的同学一定知道在java中处理并发主要有两种方式:

1,synchronized关键字,这个大家应当都各种面试和笔试中经常遇到。

2,volatile修饰符的使用,相信这个修饰符大家平时在项目中使用的也不是很多。

 

这里重点说一下volatile:

Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存重新读取该成员的值,而且,当成员变量值发生变化时,强迫将变化的值重新写入共享内存,这样两个不同的线程在访问同一个共享变量的值时,始终看到的是同一个值。

 

java语言规范指出:为了获取最佳的运行速度,允许线程保留共享变量的副本,当这个线程进入或者离开同步代码块时,才与共享成员变量进行比对,如果有变化再更新共享成员变量。这样当多个线程同时访问一个共享变量时,可能会存在值不同步的现象。

 

而volatile这个值的作用就是告诉VM:对于这个成员变量不能保存它的副本,要直接与共享成员变量交互。

 

建议:当多个线程同时访问一个共享变量时,可以使用volatile,而当访问的变量已在synchronized代码块中时,不必使用。

缺点:使用volatile将使得VM优化失去作用,导致效率较低,所以要在必要的时候使用。

 

 

分享到:
评论
7 楼 dxqrr 2015-03-06  
确实不是因为volatile 关键字的原因
6 楼 紫藤萝 2014-08-13  
ydm305365 写道
看这篇文章的同仁,请不要被本文的作者误导,使用volatile关键字,并不能保证i++,操作的原子性,volatile解决的只是多线程间共享变量的可见性问题,自己可以随便写个用volatile修饰的变量,然后用多线程多跑i++,这种方法,很容易发现问题所在。

最近在看多线程并发的问题,想知道这个volatile应用场景,麻烦解说下。
5 楼 ydm305365 2014-06-08  
AtomicInteger之所以能够实现原子递增,并不是因为使用了volatile关键字,而是因为unsafe,真正核心的方法,请查看源码

   public final int incrementAndGet() {  
       for (;;) {  
           //这里可以拿到value的最新值  
           int current = get();  
           int next = current + 1;  
           if (compareAndSet(current, next))  
               return next;  
       }  
   } 


compareAndSet主要在这个方法上,这个方法主要通过CAS算法,具体什么可以
可以查看这篇文章
http://caogen81.iteye.com/blog/2002884
4 楼 ydm305365 2014-06-08  
看这篇文章的同仁,请不要被本文的作者误导,使用volatile关键字,并不能保证i++,操作的原子性,volatile解决的只是多线程间共享变量的可见性问题,自己可以随便写个用volatile修饰的变量,然后用多线程多跑i++,这种方法,很容易发现问题所在。
3 楼 cha_bill 2013-10-22  
你这个类不是线程安全的类,虽然你用了AtomicInteger,你这段代码只能保证map中的Integer是线程安全的,但是你使用了,HashMap,这个类不是线程安全的,所以你这个类,从你贴上的代码来看,不是线程安全的。
2 楼 greenwen 2013-09-13  
jsbanh0 写道
有个问题,Atomic类型的变量为何是线程安全的原因是因为 使用volatile修饰。
根据楼主的判断,那么下述代码中的两个变量会是相同的结果,但实际运行并非如此,详见
http://raychase.iteye.com/blog/1679131一文,那这不是互相矛盾的么,还是我理解错了呢
private static volatile int nonAtomicCounter = 0;
private static volatile AtomicInteger atomicCounter = new AtomicInteger(0);

nonAtomicCounter++;
atomicCounter.incrementAndGet();
 

nonAtomicCounter++ 先判断值 再自增
++nonAtomicCounter是先自增再判断值
这两个的结果是不同的

++nonAtomicCounter
atomicCounter.incrementAndGet()
这两个结果才相同
1 楼 jsbanh0 2012-09-18  
有个问题,Atomic类型的变量为何是线程安全的原因是因为 使用volatile修饰。
根据楼主的判断,那么下述代码中的两个变量会是相同的结果,但实际运行并非如此,详见
http://raychase.iteye.com/blog/1679131一文,那这不是互相矛盾的么,还是我理解错了呢
private static volatile int nonAtomicCounter = 0;
private static volatile AtomicInteger atomicCounter = new AtomicInteger(0);

nonAtomicCounter++;
atomicCounter.incrementAndGet();
 

相关推荐

    AtomicInteger并发测试

    测试java.util.concurrent.atomic.AtomicInteger的类 与直接使用int做区别

    Java中对AtomicInteger和int值在多线程下递增操作的测试

    主要介绍了Java中对AtomicInteger和int值在多线程下递增操作的测试,本文得出AtomicInteger操作 与 int操作的效率大致相差在50-80倍上下的结论,需要的朋友可以参考下

    AtomicInteger 浅谈

    NULL 博文链接:https://zcmor.iteye.com/blog/1535524

    Java AtomicInteger类的使用方法详解

    主要介绍了Java AtomicInteger类的使用方法详解,文中有具体实例代码,具有一定参考价值,需要的朋友可以了解下。

    AtomicInteger的使用,CAS的工作原理

    比较当前工作内存的值和主内存的值,如果相同则只需规定操作,否则继续比较直到内存和工作内存中的值一致为止 AtomicInteger atomicInteger = new AtomicInteger(5); atomicInteger.compareAndSet(5, 2020) + \t ...

    java并发之AtomicInteger源码分析

    AtomicInteger是java并发包下面提供的原子类,主要操作的是int类型的整型,通过调用底层Unsafe的CAS等方法实现原子操作。下面小编和大家一起学习一下

    Java AtomicInteger类使用方法实例讲解

    主要介绍了Java AtomicInteger类使用方法实例讲解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    ViewPager+AtomicInteger实现广告轮播

    利用ViewPager实现的广告轮播,没有触摸事件的时候可以定时轮播广告,有触摸事件实施触摸事件。自动轮播使用的是线程加AtomicInteger的方式实现。

    AtomicIntegerExample:AtomicInteger示例

    AtomicInteger示例AtomicInteger用于原子增量计数器之类的应用程序。 简短的示例代码: public class AtomicIntegerExample { private final ExecutorService execService = Executors . newFixedThreadPool( 100 );...

    JAVA初级面试题(release)

    NULL 博文链接:https://it-fan.iteye.com/blog/1183175

    线程基础,线程池,生命周期

    线程基础,线程池,生命周期

    使用Java的Memory Model实现一个简单的计数器.txt

    在这个计数器中,我们使用`AtomicInteger`的`incrementAndGet()`方法来实现自增操作,并使用`get()`方法来获取当前计数器的值。由于这些操作都是原子性的,因此可以保证在多线程环境下的安全性和正确性。

    Redis数据结构与对象总结

    Redis数据结构与对象总结 数据结构与对象 简单动态字符串 SDS简介 SDS与C字符串的区别 常数复杂度获取字符串长度 O(n) O(1) 杜绝缓冲区溢出 修改字符串长度时内存重分配 空间预分配:对字符串进行增长操作时...

    java 分页、批量删除

    包含了jsp的简单分页,有首页、尾页、上下页、设置页面数字等,有完整的注释、包、ppt等,mysql数据库的,对后台管理的删除有不错的参考价值,非常适合web初学者,改改就可以在多少场合运用。

    用Java代码所写的简单计数器

    用Java代码所写的简单计数器,功能:根据选票人投票,最后记录数据并用立方图显示结果

    java编发编程:JUC综合讲解

    Java 并发编程在现代软件开发中占据重要地位,尤其是在多核处理器的时代。JUC(java.util.concurrent)库是 Java 标准库的一部分,提供了丰富的多线程并发工具,旨在帮助开发者编写高性能、高可伸缩性的并发程序。...

    redis-demo:spring boot高并发秒杀测试

    redis高并发秒杀测试测试项目: : 准备使用docker-compose命令启动redis服务器(可以用其他方式... //记录实际卖出的商品数量 private AtomicInteger successNum = new AtomicInteger ( 0 ); @RequestMapping ( valu

    kotlinx.atomicfu:在Kotlin中使用原子操作的惯用方式

    kotlinx.atomicfu:在Kotlin中使用原子操作的惯用方式

    基于Java+MySQL设计与实现的秒杀与抢购模型架构【100013279】

    对高并发高负载情形下的应用场景进行分析,以高效地处理资源竞争为目的,设计一个秒杀与抢购模型。 本项目提供了三种解决方案来比较系统的性能: 1.利用MySQL的update行锁实现悲观锁。 2.MySQL加字段version实现乐观...

    java8集合源码-IteRace:Java并行循环的竞争检测

    报告应用程序中的竞争,而不是库和代码。 例如,您不必追踪发生在 HashSet 中的竞争——它只会告诉您您无意中共享了一个特定的 HashSet 对象。 基于类的线程安全模型过滤竞争。 比这稍微复杂一些,但是,例如,您...

Global site tag (gtag.js) - Google Analytics