java中的原子操作类AtomicInteger及其实现原理
阅读原文时间:2022年07月12日阅读:2
    /\*\*  
     \* 一,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

         * 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("\\n=====这是第 " + count + " 次连接=====\\n");  
                }  
            }  
        });  
    }  
    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;  
    }  
}