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

  • Post author:
  • Post category:java

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

2016年07月05日 22:40:23 春秋战国程序猿 阅读数:16230 标签: java原子操作 更多

个人分类: myeclipse自动生成激活码

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

         */

 

示例代码如下:

 

 
  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(1, 2));

  43. System.out.println("--自减后的 atomicInteger = " + atomicInteger);

  44. System.out.println("atomicInteger.getAndIncrement() = " + atomicInteger.compareAndSet(11, 9999));

  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:原子更新整形的字段的更新器

 

 

 
  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连接的情况。

 

 

 
  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>

 

 
  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. }