2013-06-20 17:12:56.0|分类: java|浏览量: 1817
|
AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。 要使用多处理器系统的功能,通常需要使用多线程构造应用程序。但是正如任何编写并发应用程序的人可以告诉你的那样,要获得好的硬件利用率,只是简单地在多个线程中分割工作是不够的,还必须确保线程确实大部分时间都在工作,而不是在等待更多的工作,或等待锁定共享数据结构。而synchronized来控制并发就需要去等待这个锁资源,这步是非常消耗资源的,处理的吞吐量也就下去了。而java的concurrent 并发包提供的AtomicInteger就提供CAS原理避免了锁等待,具体的实现是通过UnSafe类来直接操作底层的硬件资源。 cpu 硬件同步原语(compare and swap) 普通的类:
public class SynchronizedCounter {
private int value;
public synchronized int getValue(){
return value;
}
public synchronized int getNextValue(){
return value++;
}
public synchronized int getPreviousValue(){
return value--;
}
} 增加synchronized关键字的类:
public class SynchronizedCounter {
private int value;
public synchronized int getValue(){
return value;
}
public synchronized int getNextValue(){
return value++;
}
public synchronized int getPreviousValue(){
return value--;
}
} 使用原子变量的类:
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicCounter {
private final AtomicInteger value = new AtomicInteger(0);
public int getValue(){
return value.get();
}
public int getNextValue(){
return value.incrementAndGet();
}
public int getPreviousValue(){
return value.decrementAndGet();
}
} 测试类:
public class Test {
static SynchronizedCounter counteSynchronizedCounter = new SynchronizedCounter();
static AtomicCounter atomicCounter = new AtomicCounter();
public static long startTime = 0;
public static long endTime = 0;
public static void main(String[] args) {
startTime = System.currentTimeMillis();
for (int i = 0; i < 1 ; i++) {
Thread t = new Thread(runnable);
t.start();
}
}
static Runnable runnable = new Runnable() {
@Override
public void run() {
for(int i=0;i<100000000;i++){
counteSynchronizedCounter.getNextValue();
}
endTime = System.currentTimeMillis();
System.out.println(endTime-startTime);
}
};
//开三个线程用时56936,开一个线程4368
// static Runnable runnable = new Runnable() {
// @Override
// public void run() {
// for(int i=0;i<100000000;i++){
// atomicCounter.getNextValue();
// }
// endTime = System.currentTimeMillis();
// System.out.println(endTime-startTime);
// }
// };
//开三个线程用时13323,一个线程用时2288
} 上面的结果说明了原子变量比synchronized关键字的运行效率高多了。
这里解释一下, “类似于 CAS 的指令允许算法执行读-修改-写操作,而无需害怕其他线程同时修改变量,因为如果其他线程修改变量,那么 CAS 会检测它(并失败),算法可以对该操作重新计算。” CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。然后对该操作重新计算,这里解释一下AtomicInteger是怎么重新计算的? AtomicInteger中的源码: 这里使用了一个无限循环,只要没有正确返回数据就一直循环。
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
|
