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("\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;
        }
    }  

原文地址:https://www.cnblogs.com/xwb583312435/p/9007659.html

时间: 2024-10-08 12:04:44

java中的原子操作类AtomicInteger及其实现原理的相关文章

Java中的原子操作类

转载: <ava并发编程的艺术>第7章 当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可能i不等于3,而是等于2.因为A和B线程在更新变量i的时候拿到的i都是1,这就是线程不安全的更新操作,通常我们会使用synchronized来解决这个问题,synchronized会保证多线程不会同时更新变量i. 而Java从JDK 1.5开始提供了java.util.concurrent.atomic包(以

Java原子操作类AtomicInteger应用场景

Java中有那么一些类,是以Atomic开头的.这一系列的类我们称之为原子操作类.以最简单的类AtomicInteger为例.它相当于一个int变量,我们执行Int的 i++ 的时候并不是一个原子操作.而使用AtomicInteger的incrementAndGet却能保证原子操作.具体的类如下: 闲话不多说,还是用实例说话吧. 问题:现在有2个线程,分别将全局整型变量 i 进行加1.每个线程执行5000次.按照传统的int使用方式,代码如下: private static int m = 0;

java中的 FileWriter类 和 FileReader类

java中的 FileWriter类 和 FileReader类的一些基本用法 1,FileWriter类(字符输出流类) 构造方法:FileWriter fw = new FileWriter(String fileName);//创建字符输出流类对象和已存在的文件相关联.文件不存在的话,并创建. 如:FileWriter fw = new FileWriter("C:\\demo.txt"); FileWriter fw = new FileWriter(String fileNa

使用myeclipse开发java,解决java中继承JFrame类出现The type JFrame is not accessible due to restriction的问题

在java中创建窗体,导入了java中的JFrame类,之后会出现错误: Access restriction: The type QName is not accessible due to restriction on required library D:\myeclipse professer2014 可以解决的办法为: Project—>Properties—>选中Java Build Path—>选择Libraries,出现下面界面: 选中窗口中原有的JRE库,点击Remov

Java中的嵌套类和内部类

以前看<Java编程思想>的时候,看到过嵌套类跟内部类的区别,不过后来就把它们的概念给忘了吧.昨天在看<数据结构与算法分析(Java语言版)>的时候,又遇到了这个概念,当时就很大的疑惑:嵌套类跟内部类有什么区别?只有是否有关键字static的区别吗? 所以今天找了个时间查了一下两者的详细区别,总结在这篇博客中,既方便自己的复习和学习,也启示他人吧. 1,概念: 定义在一个类内部的类,叫作"嵌套类".嵌套类分为两种:static的和非static的.后者又有一个专

java中的File类

File类 java中的File类其实和文件并没有多大关系,它更像一个对文件路径描述的类.它即可以代表某个路径下的特定文件,也可以用来表示该路径的下的所有文件,所以我们不要被它的表象所迷惑.对文件的真正操作,还得需要I/O流的实现. 1.目录列表 如果我们想查看某个目录下有那些文件和目录,我们可以使用File中提供的list方式来查看,这很像linux下的ls命令. 查看E:/html文件夹下所有的php文件,执行的时候输入的参数为正则表达式 1 package com.dy.xidian; 2

java 中的String类

String a = "aaa"; 用这种方式的时候java首先在内存中寻找"aaa"字符串,如果有,就把aaa的地址给它 如果没有则创建 String a = new String("aaa"); 是不管内存中有没有"aaa" 都开辟一块新内存保存它 可以用以下方法验证下 String a = "aaa"; String b = "aaa"; String c = new String

Java中的Object类

关于Object类的equals()方法的特点: 1) 自反性:对于非空引用x来说,x.equals(x)一定返回true: 2) 对称性:对于非空引用x和y来说,如果x.equals(y)返回true,那么y.equals(x)一定返回true: 3) 传递性:对于非空引用x.y和z来说,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)一定返回true: 4) 一致性:对于非空引用x和y来说,如果x.equals(y)返回true,那么

【Java】Java中的Collections类——Java中升级版的数据结构【转】

一般来说课本上的数据结构包括数组.单链表.堆栈.树.图.我这里所指的数据结构,是一个怎么表示一个对象的问题,有时候,单单一个变量声明不堪大用,比如int,String,double甚至一维数组.二维数组无法完全表达你要表达的东西,而定义一个类Class有太过麻烦,这时候,你可以考虑一下用Java中的Collections类.使用Collections类,必须在文件头声明import java.util.*;   一.动态.有序.可变大小的一维数组Vector与ArrayList Collecti