首页 > 开发程序 > PHP > 正文


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

08-19 22:28:00   来源:   评论: 点击:

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

*

*

*/

示例代码如下:

[java] view
plain copy







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

[java] view
plain copy







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

[html] view
plain copy







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] view
plain copy







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;

}

}

相关热词搜索:

上一篇:php 读取xml 下一篇:Java中原子类的实现
分享到: 收藏