zoukankan      html  css  js  c++  java
  • java中的原子操作类AtomicInteger及其实现原理

            /**
             * 一,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:原子更新带有版本号的引用类型的更新器

               */

     

    示例代码如下:

        import java.util.concurrent.atomic.AtomicInteger;  
        import sun.misc.Unsafe;  
          
        public class TestAtomic {  
          
            /** 
             * @param java中的原子操作类AtomicInteger 
             * @author yangcq 
             *  
             * 关于AtomicInteger的说明(来自官方文档注解) 
             * /** 
             * An {@code int} value that may be updated atomically.  See the 
             * {@link java.util.concurrent.atomic} package specification for 
             * description of the properties of atomic variables. An 
             * {@code AtomicInteger} is used in applications such as atomically 
             * incremented counters, and cannot be used as a replacement for an 
             * {@link java.lang.Integer}. However, this class does extend 
             * {@code Number} to allow uniform access by tools and utilities that 
             * deal with numerically-based classes. 
             * 
             * @since 1.5 
             * @author Doug Lea 
             */  
            public static void main(String[] args) {  
                // 初始值为1  
                AtomicInteger atomicInteger = new AtomicInteger(1);  
                System.out.println("--初始值atomicInteger = " + atomicInteger);  
                  
                // 以原子方式将当前值加1,注意这里返回的是自增前的值   
                System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.getAndIncrement());  
                System.out.println("--自增后的 atomicInteger = " + atomicInteger);  
                  
                // 以原子方式将当前值减1,注意这里返回的是自减前的值   
                System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.decrementAndGet());  
                System.out.println("--自减后的 atomicInteger = " + atomicInteger);  
                  
                // 以原子方式将当前值与括号中的值相加,并返回结果  
                System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.addAndGet(10));  
                System.out.println("--自减后的 atomicInteger = " + atomicInteger);  
                  
                // 如果输入的值等于预期的值,则以原子方式将该值设置成括号中的值  
                System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.compareAndSet(1, 2));  
                System.out.println("--自减后的 atomicInteger = " + atomicInteger);  
                System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.compareAndSet(11, 9999));  
                System.out.println("--自减后的 atomicInteger = " + atomicInteger);  
                  
                /** 
                 * 一,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:原子更新带有版本号的引用类型的更新器 
                 *  
                 *  
                 */  
            }  
          
        }  

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

        import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;  
          
        public class TestAtomicIntegerFieldUpdater {  
          
            /** 
             * @param AtomicIntegerFieldUpdater:原子更新整形的字段的更新器 
             * @author yangcq 
             */  
              
            // 创建原子更新器,并设置需要更新的对象类和对象的属性  
            private static AtomicIntegerFieldUpdater<User> atomicIntegerFieldUpdater   
                = AtomicIntegerFieldUpdater.newUpdater(User.class, "age");  
              
            public static void main(String[] args) {  
                  
                // 设置age的初始值为1000  
                User user = new User();  
                user.setUserName("yangcq");  
                user.setAge(1000);  
                  
                // 原子更新引用数据类型的字段值  
                System.out.println(atomicIntegerFieldUpdater.getAndIncrement(user));  
                // 更新以后的值  
                System.out.println(atomicIntegerFieldUpdater.get(user));  
            }  
              
            //实体类User  
            public static class User{  
                private String userName;  
                public volatile int age;  
          
                // setter、getter方法  
                public String getUserName() {  
                    return userName;  
                }  
                public void setUserName(String userName) {  
                    this.userName = userName;  
                }  
                public int getAge() {  
                    return age;  
                }  
                public void setAge(int age) {  
                    this.age = age;  
                }  
            }  
          
        }  

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

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

        bean配置如下:  
            <bean id="Httpclient" name="httpclient" class="com.yangcq.initBean.HttpClientFacotryBean">  
                <property name="connectionManager" ref="connectionManagers" ></property>  
                <property name="map">  
                    <map>  
                        <entry key="http.socket.timeout" value="30000" />  
                        <entry key="http.connection.timeout" value="30000" />  
                        <entry key="http.conn-manager.timeout"  value="6000" />  
                    </map>  
                </property>  
            </bean>  
        java实现类:  
        import java.io.IOException;  
        import java.util.Map;  
        import java.util.concurrent.atomic.AtomicInteger;  
        import org.apache.http.HttpException;  
        import org.apache.http.HttpRequest;  
        import org.apache.http.HttpRequestInterceptor;  
        import org.apache.http.client.HttpClient;  
        import org.apache.http.conn.ClientConnectionManager;  
        import org.apache.http.conn.params.ConnManagerPNames;  
        import org.apache.http.conn.params.ConnManagerParamBean;  
        import org.apache.http.impl.client.DefaultHttpClient;  
        import org.apache.http.params.BasicHttpParams;  
        import org.apache.http.params.CoreConnectionPNames;  
        import org.apache.http.params.HttpConnectionParamBean;  
        import org.apache.http.params.HttpParams;  
        import org.apache.http.protocol.HttpContext;  
        import org.apache.log4j.Logger;  
        import org.springframework.beans.factory.BeanInitializationException;  
        import org.springframework.beans.factory.DisposableBean;  
        import org.springframework.beans.factory.FactoryBean;  
        import org.springframework.beans.factory.InitializingBean;  
        /** 
         * 在容器启动时注入connectionManager,然后初始化httpClient 
         * 主要参数: 
         * CONNECTION_TIMEOUT : 连接主机超时时间设置 
         * SO_TIMEOUT :         读取主机数据超时时间设置 
         * TIMEOUT :            获取连接超时时间 
         */  
        public class HttpClientFacotryBean implements FactoryBean,InitializingBean,DisposableBean {  
            private static final Logger logger = Logger.getLogger(HttpClientFacotryBean.class);  
            private DefaultHttpClient httpClient;  
            private ClientConnectionManager clientConnectionManager = null;  
            private Map map = null;   
            //设置httpClient超时参数  
            public void afterPropertiesSet() throws Exception {  
                if (null == clientConnectionManager) {  
                    throw new BeanInitializationException("The connection manager must be set in " + this.getClass().getName() + "...");  
                }  
                HttpParams httpParams = new BasicHttpParams();  
                if (null != map) {  
                    HttpConnectionParamBean httpConnectionParamBean = new HttpConnectionParamBean(httpParams);  
                    String connectionTimeout = (String) map.get(CoreConnectionPNames.CONNECTION_TIMEOUT);  
                    if (null != connectionTimeout)  
                        httpConnectionParamBean.setConnectionTimeout(Integer.parseInt(connectionTimeout));  
                    String soTimeout = (String) map.get(CoreConnectionPNames.SO_TIMEOUT);  
                    if (null != connectionTimeout)  
                        httpConnectionParamBean.setSoTimeout(Integer.parseInt(soTimeout));  
                    ConnManagerParamBean connManagerParamBean = new ConnManagerParamBean(httpParams);  
                    String timeout = (String) map.get(ConnManagerPNames.TIMEOUT);  
                    if (null != timeout)  
                        connManagerParamBean.setTimeout(Long.parseLong(timeout));  
                }  
                this.httpClient = new DefaultHttpClient(clientConnectionManager, httpParams);  
                this.httpClient.addRequestInterceptor(new HttpRequestInterceptor() {  
                    public void process(final HttpRequest request,final HttpContext context) throws HttpException,IOException {  
                        AtomicInteger count = (AtomicInteger) context.getAttribute("count"); // 从HttpContext中获取计数器count  
                        if (null == count) {  
                            count = new AtomicInteger(1); // 如果计数器为空,则初始化值为1  
                            context.setAttribute("count", count); // 放到context中  
                        }  
                        request.addHeader("Count", Integer.toString(count.getAndIncrement())); // 把计数器放到request请求中  
                        if (logger.isDebugEnabled()) {  
                            logger.debug("
    =====这是第 " + count + " 次连接=====
    ");  
                        }  
                    }  
                });  
            }  
            public void destroy() throws Exception {  
                if (null != params)  
                    map.clear();  
                if (null != clientConnectionManager)  
                    clientConnectionManager.closeExpiredConnections();  
            }  
            public ClientConnectionManager getConnectionManager() {  
                return clientConnectionManager;  
            }  
            public Map getParams() {  
                return map;  
            }  
            public void setConnectionManager(ClientConnectionManager clientConnectionManager) {  
                this.clientConnectionManager = clientConnectionManager;  
            }  
            public void setParams(Map map) {  
                this.map = map;  
            }  
            public Object getObject() throws Exception {  
                return this.httpClient;  
            }     
            public Class getObjectType() {  
                return HttpClient.class;  
            }  
            public boolean isSingleton() {  
                return false;  
            }  
        }  
  • 相关阅读:
    现有某电商网站用户对商品的收藏数据,记录了用户收藏的商品id以及收藏日期,名为buyer_favorite1。 buyer_favorite1包含:买家id,商品id,收藏日期这三个字段,数据以“ ”分割
    面向对象程序设计中类与类的关系都有哪几种?分别用类图实例说明。
    Java为什么没有指针
    touchz,mkdir,vi的区别
    session使用方法
    迪杰斯特拉算法-文档读取数据
    数据结构---公交线路提示系统(Java后台+excel表格+web前端)
    caffe中train过程的train数据集、val数据集、test时候的test数据集区别
    caffe程序中出现的db.cpp:#line(行号) unknown database backend问题
    caffe的cancat层
  • 原文地址:https://www.cnblogs.com/xwb583312435/p/9007659.html
Copyright © 2011-2022 走看看