AtomicIntegerFieldUpdater可以保证对象属性的原子性
AtomicIntegerFieldUpdater测试类
package com.dwz.atomicApi;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class AtomicIntegerFieldUpdaterTest {
public static void main(String[] args) {
AtomicIntegerFieldUpdater<TestMe> updater = AtomicIntegerFieldUpdater.newUpdater(TestMe.class, "i");
TestMe me = new TestMe();
for(int i = 0; i < 2; i++) {
new Thread() {
public void run() {
for(int i = 0; i < 20; i++) {
int v = updater.getAndIncrement(me);
System.out.println(Thread.currentThread().getName() + "=>" + v);
}
}
}.start();
}
}
static class TestMe {
volatile int i;
}
}
测试结果正常
有几种情况会导致AtomicIntegerFieldUpdater失败
情况一:不能访问同包类中的私有变量
目标类
package concurrency;
public class TestMe {
private volatile int i;
}
AtomicIntegerFieldUpdater测试类
package concurrency;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import org.junit.Test;
public class FailedAtomicIntegerFieldUpdaterTest {
@Test(expected = RuntimeException.class)
public void testPrivateFieldAccessError() {
AtomicIntegerFieldUpdater<TestMe> updater = AtomicIntegerFieldUpdater.newUpdater(TestMe.class, "i");
TestMe me = new TestMe();
updater.compareAndSet(me, 0, 1);
}
}
不加@Test(expected = RuntimeException.class)会出错
java.lang.RuntimeException: java.lang.IllegalAccessException: Class concurrency.FailedAtomicIntegerFieldUpdaterTest can not access a member of class concurrency.TestMe with modifiers "private volatile"
at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl.<init>(AtomicIntegerFieldUpdater.java:405)
at java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdater.java:88)
at concurrency.FailedAtomicIntegerFieldUpdaterTest.testPrivateFieldAccessError(FailedAtomicIntegerFieldUpdaterTest.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Caused by: java.lang.IllegalAccessException: Class concurrency.FailedAtomicIntegerFieldUpdaterTest can not access a member of class concurrency.TestMe with modifiers "private volatile"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at sun.reflect.misc.ReflectUtil.ensureMemberAccess(ReflectUtil.java:103)
at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl.<init>(AtomicIntegerFieldUpdater.java:394)
... 25 more
意思是不能访问同包类中的私有变量
情况二:访问的对象不能是null
目标类
package concurrency;
public class TestMe {
volatile int i;
}
测试类
package concurrency;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import org.junit.Test;
public class FailedAtomicIntegerFieldUpdaterTest {
@Test
public void testTargetObjectIsNull() {
AtomicIntegerFieldUpdater<TestMe> updater = AtomicIntegerFieldUpdater.newUpdater(TestMe.class, "i");
updater.compareAndSet(null, 0, 1);
}
}
测试结果:
java.lang.ClassCastException
at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl.throwAccessCheckException(AtomicIntegerFieldUpdater.java:475)
at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl.accessCheck(AtomicIntegerFieldUpdater.java:466)
at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl.compareAndSet(AtomicIntegerFieldUpdater.java:488)
at concurrency.FailedAtomicIntegerFieldUpdaterTest.testTargetObjectIsNull(FailedAtomicIntegerFieldUpdaterTest.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
情况三:目标对象的字段名称错误
目标类
package concurrency; public class TestMe { volatile int i; }
测试类
package concurrency;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import org.junit.Test;
public class FailedAtomicIntegerFieldUpdaterTest {
@Test
public void testFieldNameInvalid() {
AtomicIntegerFieldUpdater<TestMe> updater = AtomicIntegerFieldUpdater.newUpdater(TestMe.class, "i1");
TestMe me = new TestMe();
updater.compareAndSet(me, 0, 1);
}
}
测试结果
java.lang.RuntimeException: java.lang.NoSuchFieldException: i1 at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl.<init>(AtomicIntegerFieldUpdater.java:403) at java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdater.java:88) at concurrency.FailedAtomicIntegerFieldUpdaterTest.testFieldNameInvalid(FailedAtomicIntegerFieldUpdaterTest.java:24) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209) Caused by: java.lang.NoSuchFieldException: i1 at java.lang.Class.getDeclaredField(Class.java:2070) at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl$1.run(AtomicIntegerFieldUpdater.java:390) at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl$1.run(AtomicIntegerFieldUpdater.java:388) at java.security.AccessController.doPrivileged(Native Method) at java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl.<init>(AtomicIntegerFieldUpdater.java:387) ... 25 more
情况四:目标对象的字段类型调用错误
测试类
package concurrency; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.junit.Test; public class FailedAtomicIntegerFieldUpdaterTest { @Test public void testFieldTypeInvalid() { AtomicReferenceFieldUpdater<TestMe2, Long> updater = AtomicReferenceFieldUpdater.newUpdater(TestMe2.class, Long.class, "i"); TestMe2 me = new TestMe2(); updater.compareAndSet(me, 0L, 1L); } static class TestMe2 { volatile Integer i; } }
测试结果
java.lang.ClassCastException
情况五:目标对象字段没有用volatile修饰
package concurrency; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.junit.Test; public class FailedAtomicIntegerFieldUpdaterTest { static class TestMe2 { Integer i; } @Test public void testFieldIsNotVolatile() { AtomicReferenceFieldUpdater<TestMe2, Integer> updater = AtomicReferenceFieldUpdater.newUpdater(TestMe2.class, Integer.class, "i"); TestMe2 me = new TestMe2(); updater.compareAndSet(me, 0, 1); } }
测试结果:
java.lang.IllegalArgumentException: Must be volatile type
总结:
使用AtomicXXXFieldUpdater的原因
a.想让类的属性操作具有原子性:
1.必须是volatile修饰
2.非private,protected(如果是当前类也可以)
3.类型必须一致
b.不想使用锁(包括显示锁和重量级锁synchronized)
c.大量需要原子类型修饰的对象,相对耗费内存,AtomicXXXFieldUpdater至少可以省一半内存