• 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至少可以省一半内存

  • 相关阅读:
    HDU1029 Ignatius and the Princess IV
    UVA11039 Building designing【排序】
    UVA11039 Building designing【排序】
    POJ3278 HDU2717 Catch That Cow
    POJ3278 HDU2717 Catch That Cow
    POJ1338 Ugly Numbers(解法二)
    POJ1338 Ugly Numbers(解法二)
    UVA532 Dungeon Master
    UVA532 Dungeon Master
    POJ1915 Knight Moves
  • 原文地址:https://www.cnblogs.com/zheaven/p/13157887.html
Copyright © 2020-2023  润新知