/**
* 一,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. 攻防世界 WEB 高手进阶区 PHP2 Writeup

    攻防世界 WEB 高手进阶区 PHP2 Writeup 题目介绍 题目考点 url 二次解码 index.phps 文件(第一次使用dirsearch可能扫不到,需要加到工具字典里) php 简单语法 ...

  2. vue强制组件重新渲染

    有时候,依赖 Vue 响应方式来更新数据是不够的,相反,我们需要手动重新渲染组件来更新数据.或者,我们可能只想抛开当前的DOM,重新开始.那么,如何让Vue以正确的方式重新呈现组件呢? 强制 Vue ...

  3. Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create()

    在Java中处理JSON格式的数据时,Google  Gson 是个不错的选择,用起来挺方便的,也有一定灵活性.我现在工作中在参与的两个项目里都有用它.不过它在处理Date格式时有个小陷阱,在不同环境 ...

  4. 记一次性能优化的心酸历程【Flask+Gunicorn+pytorch+多进程+线程池,一顿操作猛如虎】

    您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦. 本文只是记录我优化的心酸历程.无他,唯记录尔.....小伙伴们可围观,可打call,可以私信与我交流. 干货满满,建议收藏,需要用到时常看看. 小 ...

  5. WPF仿Tabcontrol加载切换多个不同View

    在同一块区域显示不同的视图内容,直接使用Tabcontrol,可能要重写TabItem的控件模板,最直接的方法通过按钮的切换,控制一个ContentControl的Content值,实现切换不同的视图 ...

  6. myeclipse重写快捷键

    shift+alt+s 点击Override/Implments methods

  7. c语言循环位移(数字,字符串)

    C语言中没有提供循环移位的操作符,但可以通过简洁的方式实现循环移位 设一个操作数x有s位则循环左移n位的操作为: (x << n) | (x >> (s - n)); 同理右移 ...

  8. [luogu4718]Pollard-Rho算法

    模板题 题解主要分为两部分,即Miller-Robin判素数以及关于Pollard-Rho算法 1.Miller-Robin判素数 对于一个数$n$,判定其是否为素数,依次执行以下几步-- (1)若$ ...

  9. [luogu5464]缩小社交圈

    不难证明合法当且仅当满足一下两个条件: 1.每一个位置最多被覆盖两次(无环) 2.将选择的区间按左端点从小到大排序,对于每一个左端点,其之前的区间的最大右端点不小于其(连通) (关于第一个的充分性证明 ...

  10. [bzoj1177]Oil

    考虑将三个矩形按某种方式划分为再三个大矩形中找最大值,容易发现只有6种划分方式,分为两类:1.4种,考虑第一条横/竖和第二条在第一条的两侧,这一类情况只需要预处理出左上/左下/右上/右下的最大子矩阵即 ...