AtomicInteger

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

Java代码   收藏代码
  1. CashierContext类部分代码:  
  2.   
  3. private Map<String, AtomicInteger> counter          = new HashMap<String, AtomicInteger>();  
  4.   
  5.   
  6. private void initCounter() {  
  7.      counter.put("cvm", new AtomicInteger(0));  
  8. }  
  9.   
  10. //被调用一次自动+1  
  11.   
  12. public MobileCashierViewModel getCvm() {  
  13.   
  14.         if (cvm != null) {  
  15.             counter.get("cvm").incrementAndGet();  
  16.         }  
  17.         return cvm;  
  18.     }  
 

使用场景:面试

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

 

 

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

 

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

 

 

Java代码   收藏代码
  1. private volatile int value;  
 

 

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

1,synchronized关键字,这个你们应当都各类面试和笔试中常常遇到。缓存

2,volatile修饰符的使用,相信这个修饰符你们平时在项目中使用的也不是不少。安全

 

这里重点说一下volatile:cookie

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

 

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

 

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

 

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

缺点:使用volatile将使得VM优化失去做用,致使效率较低,因此要在必要的时候使用。

 

 

分享到:   
参考知识库
人工智能知识库3342  关注 | 409  收录
MongoDB知识库5177  关注 | 303  收录
Hbase知识库6169  关注 | 63  收录
区块链知识库3013  关注 | 105  收录
评论
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,真正核心的方法,请查看源码

Java代码   收藏代码
  1. public final int incrementAndGet() {    
  2.     for (;;) {    
  3.         //这里能够拿到value的最新值    
  4.         int current = get();    
  5.         int next = current + 1;    
  6.         if (compareAndSet(current, next))    
  7.             return next;    
  8.     }    
  9. }   

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一文,那这不是互相矛盾的么,仍是我理解错了呢
Java代码   收藏代码
  1. private static volatile int nonAtomicCounter = 0;  
  2. private static volatile AtomicInteger atomicCounter = new AtomicInteger(0);  
  3.   
  4. nonAtomicCounter++;  
  5. atomicCounter.incrementAndGet();  
  

Java代码   收藏代码
  1. nonAtomicCounter++ 先判断值 再自增  
  2. ++nonAtomicCounter是先自增再判断值  
  3. 这两个的结果是不一样的  
  4.   
  5. ++nonAtomicCounter  
  6. atomicCounter.incrementAndGet()  
  7. 这两个结果才相同  
1 楼  jsbanh0 2012-09-18  
有个问题,Atomic类型的变量为什么是线程安全的缘由是由于 使用volatile修饰。
根据楼主的判断,那么下述代码中的两个变量会是相同的结果,但实际运行并不是如此,详见
http://raychase.iteye.com/blog/1679131一文,那这不是互相矛盾的么,仍是我理解错了呢
Java代码   收藏代码
  1. private static volatile int nonAtomicCounter = 0;  
  2. private static volatile AtomicInteger atomicCounter = new AtomicInteger(0);  
  3.   
  4. nonAtomicCounter++;  
  5. atomicCounter.incrementAndGet();  
相关文章
相关标签/搜索