您的位置:首页 > 编程语言 > Java开发

[Java多线程]-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析

2017-03-24 11:17 525 查看
Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作.

一、Atomic包下的所有类如下表:

类摘要
AtomicBoolean可以用原子方式更新的
boolean
值。
AtomicInteger可以用原子方式更新的
int
值。
AtomicIntegerArray可以用原子方式更新其元素的
int
数组。
AtomicIntegerFieldUpdater<T>基于反射的实用工具,可以对指定类的指定
volatileint
字段进行原子更新。
AtomicLong可以用原子方式更新的
long
值。
AtomicLongArray可以用原子方式更新其元素的
long
数组。
AtomicLongFieldUpdater<T>基于反射的实用工具,可以对指定类的指定
volatilelong
字段进行原子更新。
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源码:

/**
* 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 finallong serialVersionUID = -1848883965231344442L;

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static finallong 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 finalvoid set(V newValue) {
value = newValue;
}

/**
* Eventually sets to the given value.
*
* @param newValue the new value
* @since 1.6
*/
public finalvoid 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 finalboolean 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 finalboolean 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 staticvoid 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大家可以看这篇博客。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: