volatile类型的实例变量的修改,JDK提供了J.U.C下的atomic包下类来支持。
1 2 3
| 1、AtomicInteger/AtomicLong/AtomicBoolean/AtomicReference是关于对变量的原子更新, 2、AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray是关于对数组的原子更新 3、AtomicIntegerFieldUpdater<T>/AtomicLongFieldUpdater<T>/AtomicReferenceFieldUpdater<T,V>是基于反射的原子更新字段的值。
|
这里也有一些约束,只能是非final的实例变量,并且被volatile修饰。
简单示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Mock { private volatile String[] name = new String[]{}; private volatile int index = 0;
private static AtomicIntegerFieldUpdater indexUpdater = AtomicIntegerFieldUpdater.newUpdater(Mock.class, "index");
private static final AtomicReferenceFieldUpdater<Mock, String[]> nameUpdater = AtomicReferenceFieldUpdater.newUpdater(Mock.class, String[].class, "name");
public int getAndIncrementIndex() { return indexUpdater.getAndIncrement(this); }
public String[] getName() { nameUpdater.set(this, new String[]{"zero"}); return nameUpdater.get(this); } }
|
AtomicXxxFieldUpdater本质上通过sun.misc.Unsafe来完成操作,在java.util.concurrent.locks包中可以发现很多Unsafe的使用痕迹,例如AbstractQueuedSynchronizer。
Unsafe提供了static方法来获取Unsafe的类变量theUnsafe,即一个Unsafe对象:
1 2 3 4 5 6 7 8 9
| @CallerSensitive public static Unsafe getUnsafe() { Class var0 = Reflection.getCallerClass(); if(!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe"); } else { return theUnsafe; } }
|
但是,可以发现,只有调用类的ClassLoader是Bootstrp ClassLoader能返回这个theUnsafe,否则会抛出SecurityException异常。因为这个类如其名,unsafe,该类设计初衷也不想被应用程序使用,只能被rt.jar中的类使用。但是实际上是可以通过反射机制拿到这个值的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class UnsafeFactory { private static final Unsafe UNSAFE;
static { Unsafe unsafe; try { Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); unsafeField.setAccessible(true); unsafe = (Unsafe) unsafeField.get(null); } catch (Throwable t) { System.out.println("sun.misc.Unsafe.theUnsafe: unavailable, {}.");
unsafe = null; } UNSAFE = unsafe; }
public static Unsafe getUnsafe() { return UNSAFE; }
private UnsafeFactory() { throw new RuntimeException("Cann't Access UnsafeFactory Constructor"); } }
|
然后就可以用Unsafe来完成对volatile变量的修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Mock { private volatile int index = 0;
private static final Unsafe unsafe = UnsafeFactory.getUnsafe(); private static final long indexOffset;
static { try { indexOffset = unsafe.objectFieldOffset(Mock.class.getDeclaredField("index")); } catch (Exception ex) { throw new Error(ex); } }
public int getAndAddIndex(int i) { return unsafe.getAndAddInt(this, indexOffset, i); } }
|