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:原子更新带有版本号的引用类型的更新器
*
*
*/
示例代码如下:
-
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; -
} -
}