java中Atomic变量的实现原理是怎么样的( 六 )

标量类:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference数组类:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray更新器类:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater复合变量类:AtomicMarkableReference,AtomicStampedReference
第一组AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference这四种基本类型用来处理布尔,整数,长整数,对象四种数据,其内部实现不是简单的使用synchronized,而是一个更为高效的方式CAS (compare and swap) + volatile和native方法,从而避免了synchronized的高开销,执行效率大为提升。我们来看个例子,与我们平时i++所对应的原子操作为:getAndIncrement()
public static void main(String args) { AtomicInteger ai = new AtomicInteger(); System.out.println(ai); ai.getAndIncrement(); System.out.println(ai); } 我们可以看一下AtomicInteger的实现:
/** * Atomically increments by one the current value. * * @return the previous value */ public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } 这里直接调用一个叫Unsafe的类去处理,看来我们还需要继续看一下unsafe类的源码了。JDK8中sun.misc下UnSafe类,
从源码注释得知,这个类是用于执行低级别、不安全操作的方法集合。尽管这个类和所有的方法都是公开的(public),但是这个类的使用仍然受限,你无法在自己的java程序中直接使用该类,因为只有授信的代码才能获得该类的实例。所以我们平时的代码是无法使用这个类的,因为其设计的操作过于偏底层,如若操作不慎可能会带来很大的灾难,所以直接禁止普通代码的访问,当然JDK使用是没有问题的。
Atomic中的CAS从前面的解释得知,CAS的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值,此处这个“原本的一个值”怎么来,我们看看AtomicInteger里的实现:
// 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); } }
/** * Report the location of a given static field, in conjunction with {@link * #staticFieldBase}. * \u0026lt;p\u0026gt;Do not expect to perform any sort of arithmetic on this offset; * it is just a cookie which is passed to the unsafe heap memory accessors. * * \u0026lt;p\u0026gt;Any given field will always have the same offset, and no two distinct * fields of the same class will ever have the same offset. * * \u0026lt;p\u0026gt;As of 1.4.1, offsets for fields are represented as long values, * although the Sun JVM does not use the most significant 32 bits. * It is hard to imagine a JVM technology which needs more than * a few bits to encode an offset within a non-array object, * However, for consistency with other methods in this class, * this method reports its result as a long value. * @see #getInt(Object, long) */ public native long objectFieldOffset(Field f); 这个方法是用来拿到我们上文提到的这个“原来的值”的内存地址。是一个本地方法,返回值是valueOffset。它的参数field就是AtomicInteger里定义的value属性:
推荐阅读
- dart这编程语言现在发展怎么样了,语法与Java,c#很相似,甚至更简洁
- Java工程师和C++工程师在工作上有啥区别哪个更适合自身发展
- 27岁,转行java的血与泪,该何去何从
- 怎样统计工程中未使用的java类
- 新互联网网站用Java还靠谱么对比Php,Python,Ruby的话
- 我想学java和安卓软件开发?
- 学计算机专业,java那些和网站开发选台式还是笔记本好
- JAVA设计思路
- 本人大专毕业一年,想要去培训,定了JAVAEE和安卓两个方向,应该学那个纠结,求帮助
- 从未接触过软件测试和java,可以学习主要是自学这两种其一吗
