Java AtomicLong
来源:互联网 发布:淘宝手机使用模板 编辑:程序博客网 时间:2024/06/03 01:10
1、为什么要用AtomicLong
原始的数据类型long和Long,没有实现同步,在多线程的情况下会出现错误。有人会说为什么不采用volatile关键字呢?我们知道volatile可以保证数据在不同线程之间的可见性,但是volatile又一个缺点是不保证原子性,正是这个原因无法保证每次更新操作都是正确的。
正是上面的原因,jdk1.5之后出现了AtomicLong,实现了long的原子操作。
2、AtomicLong分析
来看看AtomicLong实现了哪些原子操作。
1)getAndIncrement()
获得数据的同时,进行自增操作。
public final long getAndIncrement() {// 死循环保证并发性 while (true) {// 获取当前值 long current = get();// 获取下一个值 long next = current + 1;// 利用原子CAS更新值 if (compareAndSet(current, next)) return current; } }
在采用CAS之前,如果在这之前有其他线程更新了这个值,那么当前值和预期值current就不相同,这将导致CAS失败,也就不会更新值为next。然后进入下一次循环,重新进行操作直到CAS操作成功。
如果在这之前没有其他线程更新这个值,那么当前值和预期值current相同,更新值为next,然后返回值current。
public final boolean compareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update); }
2)getAndDecrement()
获得数据的同时,进行自减操作。
3)getAndAdd(long delta)
将当前值加上delta,其实现和getAndIncrement基本一致,在一定程度上可以将后者理解为前者的特殊。
4)incrementAndGet()
获得数据的同时,进行自增操作。和getAndIncrement不同的是,其返回的值是自增之后的值。如果要用java原始的操作符解释的话,incrementAndGet可以理解为 ++i,而getAndIncrement可以立即为 i++。
5)decrementAndGet()
获得数据的同时,进行自减操作。和getAndDecrement不同的是,其返回的值是自减之后的值。如果要用java原始的操作符解释的话,decrementAndGet可以理解为 --i,而getAndDecrement可以立即为 i--。
6)addAndGet(long delta)
和getAndAdd相类似,其不同点和上面的几个不同点一样。
unsafe.compareAndSwapLong(this, valueOffSet, expect, update)如何理解呢?
第一个参数,表示该属性(需要进行CAS操作的属性)所在的对象
第二个参数,表示该属性的相对偏移量。这里的相对偏移量是指:属性所在对象的地址是A,属性的地址是B,则相对地址偏移量是B - A。
第三个参数,表示该属性预期的值。
第四个参数,表示需要更新的值。
this指向了AtomicLong的对象。而valueOffSet在类进行加载的时候就已经计算好了,因为它是一个static属性。所以对于所有的AtomicLong对象,需要更新的这个值的偏移量都是相同的。
static { try { valueOffset = unsafe.objectFieldOffset (AtomicLong.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } }
上面的静态初始块,对valueOffSet进行了设置。而其调用的是unsafe.objectFiledOffSet()。
来看看下面的例子,
import java.lang.reflect.Field;import sun.misc.Unsafe;@SuppressWarnings("restriction")public class InterruptTest {private long attr1 = 100;private long attr2 = 100;private byte attr3 = 100;private int attr4 = 100;private static long valueOffset1 = 0;private static long valueOffset2 = 0;private static long valueOffset3 = 0;private static long valueOffset4 = 0;private static Unsafe unsafe = null;static {try {unsafe = getUnsafe();// 获取偏移量valueOffset1 = unsafe.objectFieldOffset(InterruptTest.class.getDeclaredField("attr1"));valueOffset2 = unsafe.objectFieldOffset(InterruptTest.class.getDeclaredField("attr2"));valueOffset3 = unsafe.objectFieldOffset(InterruptTest.class.getDeclaredField("attr3"));valueOffset4 = unsafe.objectFieldOffset(InterruptTest.class.getDeclaredField("attr4"));} catch (Exception ex) {}}@SuppressWarnings("restriction")// 通过反射获取unsafe实例private static Unsafe getUnsafe() {try {Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");singleoneInstanceField.setAccessible(true);return (Unsafe) singleoneInstanceField.get(null);} catch (IllegalArgumentException e) {} catch (SecurityException e) {} catch (NoSuchFieldException e) {} catch (IllegalAccessException e) {}return unsafe;}public static void main(String[] args) {InterruptTest it = new InterruptTest();System.out.println(InterruptTest.valueOffset1);System.out.println(InterruptTest.valueOffset2);System.out.println(InterruptTest.valueOffset3);System.out.println(InterruptTest.valueOffset4);}}
运行程序出来的结果是,
8162824分别对应的是四个属性的偏移量。在回顾下之前的四个属性分别是long,long,byte,int,如果按照内存对其的规则,应该是8,16,24,28才对为什么最后两个反了呢?
详细的情况可以参见如下文章:
http://www.codeinstructions.com/2008/12/sizeof-for-java.html
是因为发生了属性的重排。
0 0
- Java AtomicLong
- java AtomicLong原理解析
- java AtomicLong原理解析
- AtomicLong
- AtomicLong
- java多线程--AtomicLong和LongAdder
- 每天一个Java类之AtomicLong
- java中Atomic类之AtomicLong
- java AtomicInteger、AtomicLong原理分析及测试实例
- 笑谈java并发编程五之AtomicLong*介绍
- Java多线程系列--【JUC原子类01】- AtomicLong原子类
- AtomicLong介绍
- 分享个java线程安全,自增主键id的类AtomicLong
- Java多线程系列--“JUC原子类”02之 AtomicLong原子类
- Java多线程系列--“JUC原子类”02之 AtomicLong原子类 (r)
- java.util.concurrent.atomic 并发包下的原子操作类(AtomicBoolean,AtomicInteger,AtomicLong......))
- java 原子量Atomic举例(AtomicReference )—— AtomicInteger、AtomicBoolean、AtomicLong
- AtomicLong源码分析
- bootinfo查看系统相关信息
- PHP_递归函数时return
- Linux 快捷键和命令
- MD5加密算法的简单使用
- udev详解问答
- Java AtomicLong
- Mysql架构
- 深入理解Java虚拟机读书笔记十
- 汇编移位: SHL、SHR、SAL、SAR、ROL、ROR、RCL、RCR
- SVN版本冲突解决详解
- IOS之UILabel自适应高度
- Redis配置文件参数说明
- JNI jbytearray资料
- Effective c++(笔记)----类与函数之实现