java中的原子操作类AtomicInteger及其实现原理

来源:互联网 发布:车辆轨迹 大数据分析 编辑:程序博客网 时间:2024/05/21 03:56
 /**
         * 一,AtomicInteger 是如何实现原子操作的呢?
         * 
         * 我们先来看一下getAndIncrement的源代码:
         *    public final int getAndIncrement() {
         *        for (;;) {
         *              int current = get();  // 取得AtomicInteger里存储的数值
         *            int next = current + 1;  // 加1
         *            if (compareAndSet(current, next))   // 调用compareAndSet执行原子更新操作
         *                return current;
         *        }
         *    }
         * 
         * 这段代码写的很巧妙:
         * 1,compareAndSet方法首先判断当前值是否等于current;
         * 2,如果当前值 = current ,说明AtomicInteger的值没有被其他线程修改;
         * 3,如果当前值 != current,说明AtomicInteger的值被其他线程修改了,这时会再次进入循环重新比较;
         *    
         * 注意这里的compareAndSet方法,源代码如下:
         * public final boolean compareAndSet(int expect, int update) {
         *     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
         * }
         * 
         * 调用Unsafe来实现
         * private static final Unsafe unsafe = Unsafe.getUnsafe();
         * 
         * 二,java提供的原子操作可以原子更新的基本类型有以下三个:
         * 
         * 1,AtomicBoolean
         * 2,AtomicInteger
         * 3,AtomicLong
         * 
         * 三,java提供的原子操作,还可以原子更新以下类型的值:
         * 
         * 1,原子更新数组,Atomic包提供了以下几个类:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
         * 2,原子更新引用类型,也就是更新实体类的值,比如AtomicReference<User>
         * AtomicReference:原子更新引用类型的值
         * AtomicReferenceFieldUpdater:原子更新引用类型里的字段
         * AtomicMarkableReference:原子更新带有标记位的引用类型
         * 3,原子更新字段值
         * AtomicIntegerFieldUpdater:原子更新整形的字段的更新器
         * AtomicLongFieldUpdater:原子更新长整形的字段的更新器
         * AtomicStampedReference:原子更新带有版本号的引用类型的更新器
         * 
         * 

         */


示例代码如下:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. import java.util.concurrent.atomic.AtomicInteger;  
  2. import sun.misc.Unsafe;  
  3.   
  4. public class TestAtomic {  
  5.   
  6.     /** 
  7.      * @param java中的原子操作类AtomicInteger 
  8.      * @author yangcq 
  9.      *  
  10.      * 关于AtomicInteger的说明(来自官方文档注解) 
  11.      * /** 
  12.      * An {@code int} value that may be updated atomically.  See the 
  13.      * {@link java.util.concurrent.atomic} package specification for 
  14.      * description of the properties of atomic variables. An 
  15.      * {@code AtomicInteger} is used in applications such as atomically 
  16.      * incremented counters, and cannot be used as a replacement for an 
  17.      * {@link java.lang.Integer}. However, this class does extend 
  18.      * {@code Number} to allow uniform access by tools and utilities that 
  19.      * deal with numerically-based classes. 
  20.      * 
  21.      * @since 1.5 
  22.      * @author Doug Lea 
  23.      */  
  24.     public static void main(String[] args) {  
  25.         // 初始值为1  
  26.         AtomicInteger atomicInteger = new AtomicInteger(1);  
  27.         System.out.println("--初始值atomicInteger = " + atomicInteger);  
  28.           
  29.         // 以原子方式将当前值加1,注意这里返回的是自增前的值   
  30.         System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.getAndIncrement());  
  31.         System.out.println("--自增后的 atomicInteger = " + atomicInteger);  
  32.           
  33.         // 以原子方式将当前值减1,注意这里返回的是自减前的值   
  34.         System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.decrementAndGet());  
  35.         System.out.println("--自减后的 atomicInteger = " + atomicInteger);  
  36.           
  37.         // 以原子方式将当前值与括号中的值相加,并返回结果  
  38.         System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.addAndGet(10));  
  39.         System.out.println("--自减后的 atomicInteger = " + atomicInteger);  
  40.           
  41.         // 如果输入的值等于预期的值,则以原子方式将该值设置成括号中的值  
  42.         System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.compareAndSet(12));  
  43.         System.out.println("--自减后的 atomicInteger = " + atomicInteger);  
  44.         System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.compareAndSet(119999));  
  45.         System.out.println("--自减后的 atomicInteger = " + atomicInteger);  
  46.           
  47.         /** 
  48.          * 一,AtomicInteger 是如何实现原子操作的呢? 
  49.          *  
  50.          * 我们先来看一下getAndIncrement的源代码: 
  51.          *    public final int getAndIncrement() { 
  52.          *        for (;;) { 
  53.          *            int current = get();  // 取得AtomicInteger里存储的数值 
  54.          *            int next = current + 1;  // 加1 
  55.          *            if (compareAndSet(current, next))   // 调用compareAndSet执行原子更新操作 
  56.          *                return current; 
  57.          *        } 
  58.          *    } 
  59.          *  
  60.          * 这段代码写的很巧妙: 
  61.          * 1,compareAndSet方法首先判断当前值是否等于current; 
  62.          * 2,如果当前值 = current ,说明AtomicInteger的值没有被其他线程修改; 
  63.          * 3,如果当前值 != current,说明AtomicInteger的值被其他线程修改了,这时会再次进入循环重新比较; 
  64.          *     
  65.          * 注意这里的compareAndSet方法,源代码如下: 
  66.          * public final boolean compareAndSet(int expect, int update) { 
  67.          *     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  68.          * } 
  69.          *  
  70.          * 调用Unsafe来实现 
  71.          * private static final Unsafe unsafe = Unsafe.getUnsafe(); 
  72.          *  
  73.          * 二,java提供的原子操作可以原子更新的基本类型有以下三个: 
  74.          *  
  75.          * 1,AtomicBoolean 
  76.          * 2,AtomicInteger 
  77.          * 3,AtomicLong 
  78.          *  
  79.          * 三,java提供的原子操作,还可以原子更新以下类型的值: 
  80.          *  
  81.          * 1,原子更新数组,Atomic包提供了以下几个类:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray 
  82.          * 2,原子更新引用类型,也就是更新实体类的值,比如AtomicReference<User> 
  83.          * AtomicReference:原子更新引用类型的值 
  84.          * AtomicReferenceFieldUpdater:原子更新引用类型里的字段 
  85.          * AtomicMarkableReference:原子更新带有标记位的引用类型 
  86.          * 3,原子更新字段值 
  87.          * AtomicIntegerFieldUpdater:原子更新整形的字段的更新器 
  88.          * AtomicLongFieldUpdater:原子更新长整形的字段的更新器 
  89.          * AtomicStampedReference:原子更新带有版本号的引用类型的更新器 
  90.          *  
  91.          *  
  92.          */  
  93.     }  
  94.   
  95. }  

四,AtomicIntegerFieldUpdater:原子更新整形的字段的更新器

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;  
  2.   
  3. public class TestAtomicIntegerFieldUpdater {  
  4.   
  5.     /** 
  6.      * @param AtomicIntegerFieldUpdater:原子更新整形的字段的更新器 
  7.      * @author yangcq 
  8.      */  
  9.       
  10.     // 创建原子更新器,并设置需要更新的对象类和对象的属性  
  11.     private static AtomicIntegerFieldUpdater<User> atomicIntegerFieldUpdater   
  12.         = AtomicIntegerFieldUpdater.newUpdater(User.class"age");  
  13.       
  14.     public static void main(String[] args) {  
  15.           
  16.         // 设置age的初始值为1000  
  17.         User user = new User();  
  18.         user.setUserName("yangcq");  
  19.         user.setAge(1000);  
  20.           
  21.         // 原子更新引用数据类型的字段值  
  22.         System.out.println(atomicIntegerFieldUpdater.getAndIncrement(user));  
  23.         // 更新以后的值  
  24.         System.out.println(atomicIntegerFieldUpdater.get(user));  
  25.     }  
  26.       
  27.     //实体类User  
  28.     public static class User{  
  29.         private String userName;  
  30.         public volatile int age;  
  31.   
  32.         // setter、getter方法  
  33.         public String getUserName() {  
  34.             return userName;  
  35.         }  
  36.         public void setUserName(String userName) {  
  37.             this.userName = userName;  
  38.         }  
  39.         public int getAge() {  
  40.             return age;  
  41.         }  
  42.         public void setAge(int age) {  
  43.             this.age = age;  
  44.         }  
  45.     }  
  46.   
  47. }  

五,java原子操作类在实际项目中的应用(java原子操作类的应用场景)

java原子操作类 AtomicInteger 在实际项目中的应用。HttpClientFacotryBean工厂会工作在多线程环境中,生成Httpclient,
就相当于建立HttpClient连接,通过工厂模式控制HttpClient连接,能够更好的管理HttpClient的生命周期。而我们使用java原子
操作类AtomicInteger来控制计数器,就是为了保证,在多线程的环境下,建立HttpClient连接不会出错,不会出现2个线程竞争一个
HttpClient连接的情况。


[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. bean配置如下:  
  2.     <bean id="Httpclient" name="httpclient" class="com.yangcq.initBean.HttpClientFacotryBean">  
  3.         <property name="connectionManager" ref="connectionManagers" ></property>  
  4.         <property name="map">  
  5.             <map>  
  6.                 <entry key="http.socket.timeout" value="30000" />  
  7.                 <entry key="http.connection.timeout" value="30000" />  
  8.                 <entry key="http.conn-manager.timeout"  value="6000" />  
  9.             </map>  
  10.         </property>  
  11.     </bean>  

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. java实现类:  
  2. import java.io.IOException;  
  3. import java.util.Map;  
  4. import java.util.concurrent.atomic.AtomicInteger;  
  5. import org.apache.http.HttpException;  
  6. import org.apache.http.HttpRequest;  
  7. import org.apache.http.HttpRequestInterceptor;  
  8. import org.apache.http.client.HttpClient;  
  9. import org.apache.http.conn.ClientConnectionManager;  
  10. import org.apache.http.conn.params.ConnManagerPNames;  
  11. import org.apache.http.conn.params.ConnManagerParamBean;  
  12. import org.apache.http.impl.client.DefaultHttpClient;  
  13. import org.apache.http.params.BasicHttpParams;  
  14. import org.apache.http.params.CoreConnectionPNames;  
  15. import org.apache.http.params.HttpConnectionParamBean;  
  16. import org.apache.http.params.HttpParams;  
  17. import org.apache.http.protocol.HttpContext;  
  18. import org.apache.log4j.Logger;  
  19. import org.springframework.beans.factory.BeanInitializationException;  
  20. import org.springframework.beans.factory.DisposableBean;  
  21. import org.springframework.beans.factory.FactoryBean;  
  22. import org.springframework.beans.factory.InitializingBean;  
  23. /** 
  24.  * 在容器启动时注入connectionManager,然后初始化httpClient 
  25.  * 主要参数: 
  26.  * CONNECTION_TIMEOUT : 连接主机超时时间设置 
  27.  * SO_TIMEOUT :         读取主机数据超时时间设置 
  28.  * TIMEOUT :            获取连接超时时间 
  29.  */  
  30. public class HttpClientFacotryBean implements FactoryBean,InitializingBean,DisposableBean {  
  31.     private static final Logger logger = Logger.getLogger(HttpClientFacotryBean.class);  
  32.     private DefaultHttpClient httpClient;  
  33.     private ClientConnectionManager clientConnectionManager = null;  
  34.     private Map map = null;   
  35.     //设置httpClient超时参数  
  36.     public void afterPropertiesSet() throws Exception {  
  37.         if (null == clientConnectionManager) {  
  38.             throw new BeanInitializationException("The connection manager must be set in " + this.getClass().getName() + "...");  
  39.         }  
  40.         HttpParams httpParams = new BasicHttpParams();  
  41.         if (null != map) {  
  42.             HttpConnectionParamBean httpConnectionParamBean = new HttpConnectionParamBean(httpParams);  
  43.             String connectionTimeout = (String) map.get(CoreConnectionPNames.CONNECTION_TIMEOUT);  
  44.             if (null != connectionTimeout)  
  45.                 httpConnectionParamBean.setConnectionTimeout(Integer.parseInt(connectionTimeout));  
  46.             String soTimeout = (String) map.get(CoreConnectionPNames.SO_TIMEOUT);  
  47.             if (null != connectionTimeout)  
  48.                 httpConnectionParamBean.setSoTimeout(Integer.parseInt(soTimeout));  
  49.             ConnManagerParamBean connManagerParamBean = new ConnManagerParamBean(httpParams);  
  50.             String timeout = (String) map.get(ConnManagerPNames.TIMEOUT);  
  51.             if (null != timeout)  
  52.                 connManagerParamBean.setTimeout(Long.parseLong(timeout));  
  53.         }  
  54.         this.httpClient = new DefaultHttpClient(clientConnectionManager, httpParams);  
  55.         this.httpClient.addRequestInterceptor(new HttpRequestInterceptor() {  
  56.             public void process(final HttpRequest request,final HttpContext context) throws HttpException,IOException {  
  57.                 AtomicInteger count = (AtomicInteger) context.getAttribute("count"); // 从HttpContext中获取计数器count  
  58.                 if (null == count) {  
  59.                     count = new AtomicInteger(1); // 如果计数器为空,则初始化值为1  
  60.                     context.setAttribute("count", count); // 放到context中  
  61.                 }  
  62.                 request.addHeader("Count", Integer.toString(count.getAndIncrement())); // 把计数器放到request请求中  
  63.                 if (logger.isDebugEnabled()) {  
  64.                     logger.debug("\n=====这是第 " + count + " 次连接=====\n");  
  65.                 }  
  66.             }  
  67.         });  
  68.     }  
  69.     public void destroy() throws Exception {  
  70.         if (null != params)  
  71.             map.clear();  
  72.         if (null != clientConnectionManager)  
  73.             clientConnectionManager.closeExpiredConnections();  
  74.     }  
  75.     public ClientConnectionManager getConnectionManager() {  
  76.         return clientConnectionManager;  
  77.     }  
  78.     public Map getParams() {  
  79.         return map;  
  80.     }  
  81.     public void setConnectionManager(ClientConnectionManager clientConnectionManager) {  
  82.         this.clientConnectionManager = clientConnectionManager;  
  83.     }  
  84.     public void setParams(Map map) {  
  85.         this.map = map;  
  86.     }  
  87.     public Object getObject() throws Exception {  
  88.         return this.httpClient;  
  89.     }     
  90.     public Class getObjectType() {  
  91.         return HttpClient.class;  
  92.     }  
  93.     public boolean isSingleton() {  
  94.         return false;  
  95.     }  
  96. }  
0 0
原创粉丝点击