Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作.
一、Atomic包下的所有类如下表:
类摘要 | |
AtomicBoolean | 可以用原子方式更新的 boolean 值。 |
AtomicInteger | 可以用原子方式更新的 int 值。 |
AtomicIntegerArray | 可以用原子方式更新其元素的 int 数组。 |
AtomicIntegerFieldUpdater<T> | 基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。 |
AtomicLong | 可以用原子方式更新的 long 值。 |
AtomicLongArray | 可以用原子方式更新其元素的 long 数组。 |
AtomicLongFieldUpdater<T> | 基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新。 |
AtomicMarkableReference<V> |
AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。 |
AtomicReference<V> | 可以用原子方式更新的对象引用。 |
AtomicReferenceArray<E> | 可以用原子方式更新其元素的对象引用数组。 |
AtomicReferenceFieldUpdater<T,V> | 基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。 |
AtomicStampedReference<V> |
AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。 |
二、AtomicInteger源码分析和基本的方法使用:
Atomicinteger类中的方法列表:
构造方法摘要 | |
---|---|
AtomicInteger() 创建具有初始值 0 的新 AtomicInteger。 |
|
AtomicInteger(int initialValue) 创建具有给定初始值的新 AtomicInteger。 |
方法摘要 | |
int |
addAndGet(int delta) 以原子方式将给定值与当前值相加。 |
boolean |
compareAndSet(int expect, int update) 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。 |
int |
decrementAndGet() 以原子方式将当前值减 1。 |
double |
doubleValue() 以 double 形式返回指定的数值。 |
float |
floatValue() 以 float 形式返回指定的数值。 |
int |
get() 获取当前值。 |
int |
getAndAdd(int delta) 以原子方式将给定值与当前值相加。 |
int |
getAndDecrement() 以原子方式将当前值减 1。 |
int |
getAndIncrement() 以原子方式将当前值加 1。 |
int |
getAndSet(int newValue) 以原子方式设置为给定值,并返回旧值。 |
int |
incrementAndGet() 以原子方式将当前值加 1。 |
int |
intValue() 以 int 形式返回指定的数值。 |
void |
lazySet(int newValue) 最后设置为给定值。 |
long |
longValue() 以 long 形式返回指定的数值。 |
void |
set(int newValue) 设置为给定值。 |
String |
toString() 返回当前值的字符串表示形式。 |
boolean |
weakCompareAndSet(int expect, int update) 如果当前值 == 预期值,则以原子方式将该设置为给定的更新值。 |
从类 java.lang.Number 继承的方法 |
---|
byteValue, shortValue |
从类 java.lang.Object 继承的方法 |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
AtomicInteger源码:
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/ /*
*
*
*
*
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/ package java.util.concurrent.atomic;
import sun.misc.Unsafe; /**
* 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 class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} private volatile int value; /**
* Creates a new AtomicInteger with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicInteger(int initialValue) {
value = initialValue;
} /**
* Creates a new AtomicInteger with initial value {@code 0}.
*/
public AtomicInteger() {
} /**
* Gets the current value.
*
* @return the current value
*/
public final int get() {
return value;
} /**
* Sets to the given value.
*
* @param newValue the new value
*/
public final void set(int newValue) {
value = newValue;
} /**
* Eventually sets to the given value.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
} /**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int newValue) {
for (;;) {
int current = get();
if (compareAndSet(current, newValue))
return current;
}
} /**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
} /**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
* and does not provide ordering guarantees, so is only rarely an
* appropriate alternative to {@code compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @return true if successful.
*/
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
} /**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
} /**
* Atomically decrements by one the current value.
*
* @return the previous value
*/
public final int getAndDecrement() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return current;
}
} /**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return current;
}
} /**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
} /**
* Atomically decrements by one the current value.
*
* @return the updated value
*/
public final int decrementAndGet() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return next;
}
} /**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the updated value
*/
public final int addAndGet(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return next;
}
} /**
* Returns the String representation of the current value.
* @return the String representation of the current value.
*/
public String toString() {
return Integer.toString(get());
} public int intValue() {
return get();
} public long longValue() {
return (long)get();
} public float floatValue() {
return (float)get();
} public double doubleValue() {
return (double)get();
} }
AtomicInteger
其中的属性:
private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} private volatile int value;
unsafe :java中的sun.misc.Unsafe包,提供了安全访问内存的方法。这些方法提供给java访问底层的JNI(java-native-interface),因为这些方法最终是调用c/c++实现。
valueOffset:指向相对于对象起始位置的偏移量(内存中)可以理解为引用指向的内存,通过这个值可以去内存中查找某个引用在内存的值。
value:引用的当前值[预期值E]
方法示例:
public class AtomTest {
private static AtomicInteger num = new AtomicInteger();
public static void main(String[] args) {
System.out.println(num.compareAndSet(, ));//比较并设置,用0与内存中的值比较,相等的话,修改值为1
System.out.println(num.compareAndSet(, ));//比较并设置,用0与内存中的值比较,相等的话,修改值为1
System.out.println(num.get());;//获取初值
num.set();//设置初值,
System.out.println(num.get());
System.out.println(num.decrementAndGet());//获取值自减返回减1之后的值
System.out.println(num.addAndGet());//获取值添加2然后返回添加后的值
System.out.println(num.getAndIncrement());//获取值并且自增,返回的是自增前的值
System.out.println(num.getAndAdd());
System.out.println(num.getAndDecrement());
System.out.println(num.getAndSet());
System.out.println(num.get());
}
}
运行结果:
true
false
初始化的时候赋值为0,调用从compareAndSwap(0,1)之后返回true,compareAndSwap比较并交换,比较结果相同则修改值并返回TRUE不通则返回FALSE。
看看这个方法的源码:
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
compareAndSwap:当前引用值和与要更新的值以及对象,和偏移量做参数去更新内存,根据对象和偏移量可以找到引用的内存值与引用值(期望值)作比较,相等则说明这个值在此对象获得后未被修改,那么我们就可以更新,则结果为true。这个方法就是传说中的CAS,CAS相较于synchonrized提供了一种无锁的线程安全保证。
示例中的前两个操作是一样的,我们可以理解为两个线程同时更新值为1,前一个快一点,发现更新的时候内存值未变则更新,等到第二个更新的时候原始值0与内存值(此时内存值变为1了)比较则失败返回FALSE并且不进行更新。这样就保证了一致性,而我们看到变量的值value使用voliate修饰的,保证了数据的内存可见性(一个线程修改其他线程可见)。所以多个线程并发的时候这个类代替Integer能够保证安全。
这个操作非常像数据库的乐观锁,给每个表添加一个version版本号,修改数据后要持久化先查询看版本号一致不,一致的话则持久化,不一致则重新获取值进行修改。
三、AtomicLong源码以及与AtomicInteger的不同:
package java.util.concurrent.atomic;
import sun.misc.Unsafe; /**
* A {@code long} 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 AtomicLong} is used in applications such as atomically
* incremented sequence numbers, and cannot be used as a replacement
* for a {@link java.lang.Long}. 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 class AtomicLong extends Number implements java.io.Serializable {
private static final long serialVersionUID = 1927816293512124184L; // setup to use Unsafe.compareAndSwapLong for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; /**
* Records whether the underlying JVM supports lockless
* compareAndSwap for longs. While the Unsafe.compareAndSwapLong
* method works in either case, some constructions should be
* handled at Java level to avoid locking user-visible locks.
*/
static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8(); /**
* Returns whether underlying JVM supports lockless CompareAndSet
* for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
*/
private static native boolean VMSupportsCS8(); static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicLong.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} private volatile long value; /**
* Creates a new AtomicLong with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicLong(long initialValue) {
value = initialValue;
} /**
* Creates a new AtomicLong with initial value {@code 0}.
*/
public AtomicLong() {
} /**
* Gets the current value.
*
* @return the current value
*/
public final long get() {
return value;
} /**
* Sets to the given value.
*
* @param newValue the new value
*/
public final void set(long newValue) {
value = newValue;
} /**
* Eventually sets to the given value.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(long newValue) {
unsafe.putOrderedLong(this, valueOffset, newValue);
} /**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final long getAndSet(long newValue) {
while (true) {
long current = get();
if (compareAndSet(current, newValue))
return current;
}
} /**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(long expect, long update) {
return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
} /**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
* and does not provide ordering guarantees, so is only rarely an
* appropriate alternative to {@code compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @return true if successful.
*/
public final boolean weakCompareAndSet(long expect, long update) {
return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
} /**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final long getAndIncrement() {
while (true) {
long current = get();
long next = current + 1;
if (compareAndSet(current, next))
return current;
}
} /**
* Atomically decrements by one the current value.
*
* @return the previous value
*/
public final long getAndDecrement() {
while (true) {
long current = get();
long next = current - 1;
if (compareAndSet(current, next))
return current;
}
} /**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the previous value
*/
public final long getAndAdd(long delta) {
while (true) {
long current = get();
long next = current + delta;
if (compareAndSet(current, next))
return current;
}
} /**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final long incrementAndGet() {
for (;;) {
long current = get();
long next = current + 1;
if (compareAndSet(current, next))
return next;
}
} /**
* Atomically decrements by one the current value.
*
* @return the updated value
*/
public final long decrementAndGet() {
for (;;) {
long current = get();
long next = current - 1;
if (compareAndSet(current, next))
return next;
}
} /**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the updated value
*/
public final long addAndGet(long delta) {
for (;;) {
long current = get();
long next = current + delta;
if (compareAndSet(current, next))
return next;
}
} /**
* Returns the String representation of the current value.
* @return the String representation of the current value.
*/
public String toString() {
return Long.toString(get());
} public int intValue() {
return (int)get();
} public long longValue() {
return get();
} public float floatValue() {
return (float)get();
} public double doubleValue() {
return (double)get();
} }
AtomicLong源码
关于AtomicLong的用法和AtomicInteger类似:
不同之处在于多了下面一部分:一个静态的Boolean值VM_SUPPORTS_LONG_CAS,调用一个 native方法VMSupportCS8()返回虚拟机是否支持Long类型的无锁CAS机制
/**
* Records whether the underlying JVM supports lockless
* compareAndSwap for longs. While the Unsafe.compareAndSwapLong
* method works in either case, some constructions should be
* handled at Java level to avoid locking user-visible locks.
*/
static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8(); /**
* Returns whether underlying JVM supports lockless CompareAndSet
* for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
*/
private static native boolean VMSupportsCS8();
从这里可以看出不同的VM支持的数据类型可能有所差别,因为CAS需要硬件系统的支持。
四、AtomicReference源码及使用:
/**
* An object reference that may be updated atomically. See the {@link
* java.util.concurrent.atomic} package specification for description
* of the properties of atomic variables.
* @since 1.5
* @author Doug Lea
* @param <V> The type of object referred to by this reference
*/
public class AtomicReference<V> implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L; private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicReference.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} private volatile V value; /**
* Creates a new AtomicReference with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicReference(V initialValue) {
value = initialValue;
} /**
* Creates a new AtomicReference with null initial value.
*/
public AtomicReference() {
} /**
* Gets the current value.
*
* @return the current value
*/
public final V get() {
return value;
} /**
* Sets to the given value.
*
* @param newValue the new value
*/
public final void set(V newValue) {
value = newValue;
} /**
* Eventually sets to the given value.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(V newValue) {
unsafe.putOrderedObject(this, valueOffset, newValue);
} /**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
} /**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
* and does not provide ordering guarantees, so is only rarely an
* appropriate alternative to {@code compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @return true if successful.
*/
public final boolean weakCompareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
} /**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final V getAndSet(V newValue) {
while (true) {
V x = get();
if (compareAndSet(x, newValue))
return x;
}
} /**
* Returns the String representation of the current value.
* @return the String representation of the current value.
*/
public String toString() {
return String.valueOf(get());
} }
AtomicReference源码
除了类型是个对象的之外,方法使用和AtomicInteger一模一样:
AtomicReference的使用:
import java.util.concurrent.atomic.AtomicReference; public class AtomTest {
private static AtomicReference<Pig> pigtest;
public static void main(String[] args) {
Pig pig = new Pig("猪坚强", 2);
Pig pig2 = new Pig("猪八戒", 2);
System.out.println("pig_hashCode:"+pig.hashCode());
System.out.println("pig2_hashCode:"+pig2.hashCode());
AtomTest.pigtest = new AtomicReference<Pig>(pig);
System.out.println(pigtest.get().toString());
System.out.println(pigtest.get().hashCode());
System.out.println(pigtest.compareAndSet(pig, pig2));
System.out.println(pigtest.compareAndSet(pig, pig2));
System.out.println(pigtest.get().toString());
System.out.println(pigtest.get().hashCode());
}
}
运行结果:
pig_hashCode:779824645
pig2_hashCode:420110874
[猪坚强,2]
779824645
true
false
[猪八戒,2]
420110874
第一步:先获取pigTest的toString(),和hashCode,结果是【猪坚强,2】,hashCode:779824645【我们发现hashCode居然==pig_hashCode】
第二步:进行CAS修改为pig2结果为true,再进行一次结果为FALSE,
第三步:获取pigTest的toString(),和hashCode,结果是【猪八戒,2】,hashCode:420110874【我们发现hashCode居然==pig2_hashCode】
结果说明了:pigtest是一个指向对象引用的引用,利用CAS操作可以修改pigTest指向的对象引用从而改变自身指向的对象。第一次CAS成功将pigtest指向的pig修改成了pig2.第二次CAS操作失败了,可以保证多线程并发时的安全问题。
五、总结:
Atomic包下内容并不复杂,一句话来说就是提供了CAS无锁的安全访问机制。表现出来的是通过期望值E与内存值M作比较,相同则修改内存值M为更新值U。四个参数:当前对象this,偏移量V,期望值E,更新值U。
利用CAS+voliate+native的机制保证数据操作的原子性,可见性和一致性。voliate使变量可见,CAS调用unsafe中的native方法访问系统底层的实现。unsafe中的这些方法直接操作内存,运用不当可能造成很大的问题。
其实从Atomic包中的原子类的探索中,只是想引出CAS这个概念,CAS同样提供了一种线程安全的机制,而它不同于Synchonrized,synchonrized被称之为重量级锁,原因是因为粒度太强,加锁就代表着线程阻塞,高并发访问时带来的性能问题是硬伤。
为了解决这种问题出现了两种机制:一种就是CAS,另一种是锁优化。
CAS是将阻塞下降到了底层CPU上(纯属个人理解,因为看到有权威是说存在阻塞的,可能让别的线程知道已经更改了数据并且更新失败也是一种阻塞吧),语言层面访问效率远远低于系统内部硬件上,尽管同样是阻塞,在系统内部加锁解锁的效率要高很多。但是需要的是硬件支持,不过现在绝大部分CPU都已经支持CAS了。
unsafe类:http://www.cnblogs.com/mickole/articles/3757278.html大家可以看这篇博客。