/**
* 一,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;
}
}

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

  1. Java中的原子操作类

    转载: <ava并发编程的艺术>第7章 当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可 ...

  2. 【Java并发】Java中的原子操作类

    综述 JDK从1.5开始提供了java.util.concurrent.atomic包. 通过包中的原子操作类能够线程安全地更新一个变量. 包含4种类型的原子更新方式:基本类型.数组.引用.对象中字段 ...

  3. Java原子操作类AtomicInteger应用场景

    Java中有那么一些类,是以Atomic开头的.这一系列的类我们称之为原子操作类.以最简单的类AtomicInteger为例.它相当于一个int变量,我们执行Int的 i++ 的时候并不是一个原子操作 ...

  4. Java学习技术分享:Java中的原子操作

    学习java需要有一套完整的学习线路,需要有条理性,当下学习java已经有一段时间了,由当初的懵逼状态逐渐好转,也逐渐养成了写技术学习笔记的习惯,今天总结了一下java中的原子操作. 1.Java中的 ...

  5. 【并发编程】Java中的原子操作

    什么是原子操作 原子操作是指一个或者多个不可再分割的操作.这些操作的执行顺序不能被打乱,这些步骤也不可以被切割而只执行其中的一部分(不可中断性).举个列子: //就是一个原子操作 int i = 1; ...

  6. Java并发之原子操作类汇总

    当程序更新一个变量时,如果是多线程同时更新这个变量,可能得到的结果与期望值不同.比如:有一个变量i,A线程执行i+1,B线程也执行i+1,经过两个线程的操作后,变量i的值可能不是期望的3,而是2.这是 ...

  7. java中的Atomic类

    文章目录 问题背景 Lock 使用Atomic java中的Atomic类 问题背景 在多线程环境中,我们最常遇到的问题就是变量的值进行同步.因为变量需要在多线程中进行共享,所以我们必须需要采用一定的 ...

  8. Java中的原子操作

    Java中的原子操作 原子性:指该操作不能再继续划分为更小的操作. Java中的原子操作包括: 除long和double之外的基本类型的赋值操作 所有引用reference的赋值操作 java.con ...

  9. 带有静态方法的类(java中的math类)

    带有静态方法的类通常(虽然不一定是这样)不打算被初始化. 可以用私有构造函数来限制非抽象类被初始化. 例如,java中的math类.它让构造函数标记为私有,所以你无法创建Math的实例.但Math类却 ...

随机推荐

  1. MySQL 查询语句(1)

    一:创建数据库 1:CREATE DATABASE test; //创建数据库test 2:SHOW DATABASES: //查看目前数据库中可用的数据库,默认会有系统数据库 3:USE test; ...

  2. bash: mysql: command not found(解决方法)

    执行mysql -uroot -p ,出现如图问题 解决方法如下: 执行以上命令,系统默认会查找/usr/bin下的命令,若这个命令不在该目录下,就会找不到,我们需要做的就是映射一个链接到/usr/b ...

  3. JavaScript高阶函数之filter、map、reduce

    JavaScript高阶函数 filter(过滤) 用法: 用于过滤,就是把数组中的每个元素,使用回调函数func进行校验,回调函数func返回一个布尔值,将返回值为 true 的元素放入新数组 参数 ...

  4. 怎么将本地已有的一个项目上传到新建的git仓库的方法

    将本地已有的一个非git项目上传到新建的git仓库的方法一共有两种. 一. 克隆+拷贝 第一种方法比较简单,直接用把远程仓库拉到本地,然后再把自己本地的项目拷贝到仓库中去.然后push到远程仓库上去即 ...

  5. D3.js V5 教程

    D3.js V5 教程 1.在项目中使用D3.js 2. 选择元素和设置(获取)属性 3. 绑定数据 4. 理解Update.Enter.Exit 与 添加.删除元素 未完待续..........

  6. 用 Node.js 实现的最简单的 HTTP 服务器

    用 Node.js 实现的最简单的 HTTP 服务器 //app.js var http = require('http'); http.createServer(function(req, res) ...

  7. webpack 项目接入Vite的通用方案介绍(上)

    愿景 希望通过本文,能给读者提供一个存/增量项目接入Vite的点子,起抛砖引玉的作用,减少这方面能力的建设成本 在阐述过程中同时也会逐渐完善webpack-vite-serve这个工具 读者可直接fo ...

  8. RabbitMQ Network Partitions 处理策略

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 网络分区的意义 RabbitMQ的模型 ...

  9. C语言通过指针数组和二维数组读取文件

    1 # include <stdio.h> 2 # include <stdlib.h> 3 # include <time.h> 4 # include < ...

  10. 调试:'Object reference note set to an instance of an object.'

    今天调试代码遇到一个奇怪的问题,每次调试到 var files = new List<string>()这一行代码,总是报错:System.NullReferenceException: ...