先看到类的开头,只看static代码块和value声明
代码语言:javascript复制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;
}
............................
}
比如我们使用new AtomicInteger(1);就会加载类,static静态代码块执行。使用的反射的机制得到名字是value的Field对象,再根据objectFieldOffset这个方法求出value这个变量在该对象内存中的偏移量valueOffset 。
代码语言:javascript复制public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) delta;
}
这个方法究竟是怎么保证线程安全的呢?
控制线程安全的其实就是乐观锁。 有人用jad反编译后得到
代码语言:javascript复制public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v delta));
return v;
}
public native int getIntVolatile(Object o, long offset);
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);
getIntVolatile方法和compareAndSwapInt方法是看不到源码的。经过代码测试才知道compareAndSwapInt这几个参数的意思。
此处转载请注明https://blog.csdn.net/qq_34115899
经过我的测试,比如
AtomicInteger t = new AtomicInteger(1); // ①
int ans = t.addAndGet(2); // ②
System.out.println(ans); // ③,得到的结果就是3,为什么呢?
看到这个方法compareAndSwapInt(o, offset, v, v delta);
第一个参数为这个AtomicInteger对象
第二个参数为刚刚的偏移量,这个偏移量就是AtomicInteger对象的value的地址
第三个参数就是v = getIntVolatile(o, offset);,这个v是从主存中得到的值
第四个参数是将v delta=1 2=3,为了更新对象中的value值
那么这个方法到底在干什么呢?
首先由第一个第二个参数(对象和偏移量)确定了这个AtomicInteger对象的值value=1,然后比较从主存中得到的值v=1,v==value?如果相等,那么执行value=v delta=1 2=3,因为AtomicInteger对象中的value是volatile修饰,会立马刷新到主存value=3,并且让其他的线程的工作内存的值失效,其他线程获取value也只能从主存获取,然后返回true,跳出循环,返回v=1,然后外层调用的函数还会继续加上delta,就会返回1 2的值3。
如果v!=value,那么不执行v delta,并且返回false,循环继续执行,这种情况可能是多个线程同时在更改这个AtomicInteger对象,此时说明主存中的值v和对象中的value不一样。
还有一种情况也会返回false,那就是compareAndSwapInt方法第一次执行返回true,如果没有在主存中读取值,也就是没执行getIntVolatile方法,那么往后多次一直返回false,直到调用getIntVolatile方法之后再执行一次才会返回true。
具体情境分析:
代码语言:javascript复制AtomicInteger t = new AtomicInteger(1); // ①
......
int ans = t.addAndGet(2); // ②
......
System.out.println(ans); // ③,得到的结果就是3,为什么呢?
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v delta));
return v;
}
AtomicInteger对象由两个线程共享,同时执行②操作。Thread1执行到乐观锁条件compareAndSwapInt(o, offset, v, v delta)的同时,Thread2也执行到这里,他们都获取了v=1,此时Thread1执行成功,返回true,跳出循环。
Thread2执行中,如果Thread1已经更新了value值,那么v和value不相等,返回false,继续循环,如果还没有更新value值,v==value成立,但是因为是第二次执行compareAndSwapInt,所以仍然返回false,继续循环。再从主存重新获取v值为3,然后判断根据偏移量获取value地址再取出值,发现v==value成立,第一次执行,返回true,并且会把v delta=3 2=5刷新到主存,然后返回v=3,外层还会再加delta,也就是3 2,最后返回5。整个过程利用乐观锁实现了线程安全。
两个线程执行了t.addAndGet(2);最后返回为5,而不会是3。
关于为什么compareAndSwapInt第一次返回true,第二次会返回false的测试代码,自行体会。
代码语言:javascript复制import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class Main {
static class Target{
public int value = 10;
}
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
//通过反射获得Unsafe实例,仅BootstrapClassLoader加载的类
//($JAVA_HOME/lib目录下jar包包含的类,如java.util.concurrent.atomic.AtomicInteger)
//才能通过Unsafe.getUnsafe静态方法获取
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
//获得Target实例域value
Field valueField = Target.class.getDeclaredField("value");
//实例化Target
Target t = new Target();
System.out.println("原始value值:" valueField.get(t));
//获得实例域在class文件里的偏移量
final long valueOffset = unsafe.objectFieldOffset(valueField);
int v5 = unsafe.getIntVolatile(t, valueOffset);// 从主存获取
//第一次swap
System.out.println("第一次swap(10,20)函数返回值:" unsafe.compareAndSwapInt(t, valueOffset, v5, v5 5));
System.out.println("第一次swap(10,20)后value值:" valueField.get(t));
//第二次swap
System.out.println("第2次swap(10,20)函数返回值:" unsafe.compareAndSwapInt(t, valueOffset, v5,v5 5));
System.out.println("第2次swap(10,20)后value值:" valueField.get(t));
v5 = unsafe.getIntVolatile(t, valueOffset);
//第3次swap
System.out.println("第3次swap(10,20)函数返回值:" unsafe.compareAndSwapInt(t, valueOffset, v5,v5 5));
System.out.println("第3swap(10,20)后value值:" valueField.get(t));
}
}
运行结果:
原始value值:10 第一次swap(10,20)函数返回值:true 第一次swap(10,20)后value值:15 第2次swap(10,20)函数返回值:false 第2次swap(10,20)后value值:15 第3次swap(10,20)函数返回值:true 第3swap(10,20)后value值:20