本文共 5045 字,大约阅读时间需要 16 分钟。
先看到类的开头,只看static代码块和value声明
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 。
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta; }这个方法究竟是怎么保证线程安全的呢?
控制线程安全的其实就是乐观锁。
有人用jad反编译后得到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这几个参数的意思。
此处转载请注明
经过我的测试,比如
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。
具体情境分析:
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的测试代码,自行体会。
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
=======================Talk is cheap, show me the code========================
转载地址:https://liuchenyang0515.blog.csdn.net/article/details/83018870 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!