/** * Basic tests of the API : Simple function calls to exercise all of the functions listed in the API * specification for the AtomicReferenceFieldUpdater class. */ public void testAPI() { // ================================================================================= // Create instances of AtomicReferenceFieldUpdater to work with for(int i = 0; i < updaters.length; i++) { updaters[i] = AtomicReferenceFieldUpdater.newUpdater(AtomicTestObject.class, String.class, "volatileString"); } // ================================================================================= // Basic API tests assertEquals("1 : get()", "the answer", getRandomUpdater().get(testObject1)); assertEquals("2 : get()", getRandomUpdater().get(testObject1), getRandomUpdater().get(testObject2)); assertEquals("3 : get()", getRandomUpdater().get(testObject1), getRandomUpdater().get(testObject1)); assertEquals("4 : get()", getRandomUpdater().get(testObject2), getRandomUpdater().get(testObject2)); assertEquals("5 : getAndSet()", "the answer", getRandomUpdater().getAndSet(testObject1, "the question")); assertEquals("6 : get()", "the question", getRandomUpdater().get(testObject1)); assertEquals("7 : getAndSet()", "the question", getRandomUpdater().getAndSet(testObject1, "the answer")); assertEquals("8 : compareAndSet()", true, getRandomUpdater().compareAndSet(testObject1, "the answer", "the question")); assertEquals("9 : compareAndSet()", true, getRandomUpdater().compareAndSet(testObject2, "the answer", "the question")); assertEquals("10: get()", getRandomUpdater().get(testObject1), getRandomUpdater().get(testObject2)); assertEquals("11: compareAndSet()", false, getRandomUpdater().compareAndSet(testObject1, "the answer", "the question")); assertEquals("12: compareAndSet()", true, getRandomUpdater().compareAndSet(testObject1, "the question", "the answer")); }
/** * compareAndSet in one thread enables another waiting for value * to succeed */ public void testCompareAndSetInMultipleThreads() throws Exception { x = one; final AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a; a = updaterFor("x"); Thread t = new Thread(new CheckedRunnable() { public void realRun() { while (!a.compareAndSet(AtomicReferenceFieldUpdaterTest.this, two, three)) Thread.yield(); }}); t.start(); assertTrue(a.compareAndSet(this, one, two)); t.join(LONG_DELAY_MS); assertFalse(t.isAlive()); assertSame(three, a.get(this)); }
/** * Atomically push the field to a {@link Disposable} and dispose the old content. * * @param updater the target field updater * @param holder the target instance holding the field * @param newValue the new Disposable to push * @return true if successful, false if the field contains the {@link #DISPOSED} instance. */ static <T> boolean set(AtomicReferenceFieldUpdater<T, Disposable> updater, T holder, @Nullable Disposable newValue) { for (;;) { Disposable current = updater.get(holder); if (current == DISPOSED) { if (newValue != null) { newValue.dispose(); } return false; } if (updater.compareAndSet(holder, current, newValue)) { if (current != null) { current.dispose(); } return true; } } }
/** * Atomically push the field to a {@link Disposable} and dispose the old content. * * @param updater the target field updater * @param holder the target instance holding the field * @param newValue the new Disposable to push * @return true if successful, false if the field contains the {@link #DISPOSED} instance. */ public static <T> boolean set(AtomicReferenceFieldUpdater<T, Disposable> updater, T holder, @Nullable Disposable newValue) { for (;;) { Disposable current = updater.get(holder); if (current == DISPOSED) { if (newValue != null) { newValue.dispose(); } return false; } if (updater.compareAndSet(holder, current, newValue)) { if (current != null) { current.dispose(); } return true; } } }
/** * A generic utility to atomically replace a subscription or cancel the replacement * if current subscription is marked as cancelled (as in {@link #cancelledSubscription()}) * or was concurrently updated before. * <p> * The replaced subscription is itself cancelled. * * @param field The Atomic container * @param instance the instance reference * @param s the subscription * @param <F> the instance type * * @return true if replaced */ public static <F> boolean set(AtomicReferenceFieldUpdater<F, Subscription> field, F instance, Subscription s) { for (; ; ) { Subscription a = field.get(instance); if (a == CancelledSubscription.INSTANCE) { s.cancel(); return false; } if (field.compareAndSet(instance, a, s)) { if (a != null) { a.cancel(); } return true; } } }
/** * 原子移除某个指定的sequence * * @param holder 原子更新的域所属的类对象 * @param sequenceUpdater 原子更新的域对象 * @param sequence 要移除的sequence * @param <T> * @return */ public static <T> boolean removeSequence( final T holder, final AtomicReferenceFieldUpdater<T, Sequence[]> sequenceUpdater, final Sequence sequence) { int numToRemove; Sequence[] oldSequences; Sequence[] newSequences; do { oldSequences = sequenceUpdater.get(holder); numToRemove = countMatching(oldSequences, sequence); if (0 == numToRemove) { break; } final int oldSize = oldSequences.length; newSequences = new Sequence[oldSize - numToRemove]; for (int i = 0, pos = 0; i < oldSize; i++) { final Sequence testSequence = oldSequences[i]; if (sequence != testSequence) { newSequences[pos++] = testSequence; } } } while (!sequenceUpdater.compareAndSet(holder, oldSequences, newSequences)); return numToRemove != 0; }
SafeAtomicHelper( AtomicReferenceFieldUpdater<Waiter, Thread> waiterThreadUpdater, AtomicReferenceFieldUpdater<Waiter, Waiter> waiterNextUpdater, AtomicReferenceFieldUpdater<AbstractFuture, Waiter> waitersUpdater, AtomicReferenceFieldUpdater<AbstractFuture, Listener> listenersUpdater, AtomicReferenceFieldUpdater<AbstractFuture, Object> valueUpdater) { this.waiterThreadUpdater = waiterThreadUpdater; this.waiterNextUpdater = waiterNextUpdater; this.waitersUpdater = waitersUpdater; this.listenersUpdater = listenersUpdater; this.valueUpdater = valueUpdater; }
/** * AtomicReferenceFieldUpdater getAndUpdate returns previous value * and updates result of supplied function */ public void testReferenceFieldUpdaterGetAndUpdate() { AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater(); a.set(this, one); assertEquals((Integer) 1, a.getAndUpdate(this, Atomic8Test::addInteger17)); assertEquals((Integer) 18, a.getAndUpdate(this, Atomic8Test::addInteger17)); assertEquals((Integer) 35, a.get(this)); assertEquals((Integer) 35, anIntegerField); }
/** * AtomicReferenceFieldUpdater updateAndGet updates with supplied * function and returns result. */ public void testReferenceFieldUpdaterUpdateAndGet() { AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater(); a.set(this, one); assertEquals((Integer) 18, a.updateAndGet(this, Atomic8Test::addInteger17)); assertEquals((Integer) 35, a.updateAndGet(this, Atomic8Test::addInteger17)); assertEquals((Integer) 35, a.get(this)); assertEquals((Integer) 35, anIntegerField); }
/** * AtomicReferenceFieldUpdater returns previous value and updates * with supplied function. */ public void testReferenceFieldUpdaterGetAndAccumulate() { AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater(); a.set(this, one); assertEquals((Integer) 1, a.getAndAccumulate(this, 2, Atomic8Test::sumInteger)); assertEquals((Integer) 3, a.getAndAccumulate(this, 3, Atomic8Test::sumInteger)); assertEquals((Integer) 6, a.get(this)); assertEquals((Integer) 6, anIntegerField); }
/** * AtomicReferenceFieldUpdater accumulateAndGet updates with * supplied function and returns result. */ public void testReferenceFieldUpdaterAccumulateAndGet() { AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater(); a.set(this, one); assertEquals((Integer) 7, a.accumulateAndGet(this, 6, Atomic8Test::sumInteger)); assertEquals((Integer) 10, a.accumulateAndGet(this, 3, Atomic8Test::sumInteger)); assertEquals((Integer) 10, a.get(this)); assertEquals((Integer) 10, anIntegerField); }
/** * Object arguments for parameters of type T that are not * instances of the class passed to the newUpdater call will * result in a ClassCastException being thrown. */ public void testFieldUpdaters_ClassCastException() { // Use raw types to allow passing wrong object type, provoking CCE final AtomicLongFieldUpdater longUpdater = aLongFieldUpdater(); final AtomicIntegerFieldUpdater intUpdater = anIntFieldUpdater(); final AtomicReferenceFieldUpdater refUpdater = anIntegerFieldUpdater(); final Object obj = new Object(); for (Object x : new Object[]{ new Object(), null }) { Runnable[] throwingActions = { () -> longUpdater.get(x), () -> intUpdater.get(x), () -> refUpdater.get(x), () -> longUpdater.set(x, 17L), () -> intUpdater.set(x, 17), () -> refUpdater.set(x, (Integer) 17), () -> longUpdater.addAndGet(x, 17L), () -> intUpdater.addAndGet(x, 17), () -> longUpdater.getAndUpdate(x, y -> y), () -> intUpdater.getAndUpdate(x, y -> y), () -> refUpdater.getAndUpdate(x, y -> y), () -> longUpdater.compareAndSet(x, 17L, 42L), () -> intUpdater.compareAndSet(x, 17, 42), () -> refUpdater.compareAndSet(x, (Integer) 17, (Integer) 42), }; assertThrows(ClassCastException.class, throwingActions); } }
public void checkPrivateAccess() { try { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a = AtomicReferenceFieldUpdater.newUpdater (AtomicReferenceFieldUpdaterTest.class, Integer.class, "privateField"); shouldThrow(); } catch (RuntimeException success) { assertNotNull(success.getCause()); } }
public void checkCompareAndSetProtectedSub() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a = AtomicReferenceFieldUpdater.newUpdater (AtomicReferenceFieldUpdaterTest.class, Integer.class, "protectedField"); this.protectedField = one; assertTrue(a.compareAndSet(this, one, two)); assertTrue(a.compareAndSet(this, two, m4)); assertSame(m4, a.get(this)); assertFalse(a.compareAndSet(this, m5, seven)); assertNotSame(seven, a.get(this)); assertTrue(a.compareAndSet(this, m4, seven)); assertSame(seven, a.get(this)); }
public void checkPackageAccess(AtomicReferenceFieldUpdaterTest obj) { obj.x = one; AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a = AtomicReferenceFieldUpdater.newUpdater (AtomicReferenceFieldUpdaterTest.class, Integer.class, "x"); assertSame(one, a.get(obj)); assertTrue(a.compareAndSet(obj, one, two)); assertSame(two, a.get(obj)); }
public void checkPrivateAccess(AtomicReferenceFieldUpdaterTest obj) { try { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a = AtomicReferenceFieldUpdater.newUpdater (AtomicReferenceFieldUpdaterTest.class, Integer.class, "privateField"); throw new AssertionError("should throw"); } catch (RuntimeException success) { assertNotNull(success.getCause()); } }
/** * get returns the last value set or assigned */ public void testGetSet() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a; a = updaterFor("x"); x = one; assertSame(one, a.get(this)); a.set(this, two); assertSame(two, a.get(this)); a.set(this, m3); assertSame(m3, a.get(this)); }
/** * get returns the last value lazySet by same thread */ public void testGetLazySet() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a; a = updaterFor("x"); x = one; assertSame(one, a.get(this)); a.lazySet(this, two); assertSame(two, a.get(this)); a.lazySet(this, m3); assertSame(m3, a.get(this)); }
/** * compareAndSet succeeds in changing value if equal to expected else fails */ public void testCompareAndSet() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a; a = updaterFor("x"); x = one; assertTrue(a.compareAndSet(this, one, two)); assertTrue(a.compareAndSet(this, two, m4)); assertSame(m4, a.get(this)); assertFalse(a.compareAndSet(this, m5, seven)); assertNotSame(seven, a.get(this)); assertTrue(a.compareAndSet(this, m4, seven)); assertSame(seven, a.get(this)); }
/** * repeated weakCompareAndSet succeeds in changing value when equal * to expected */ public void testWeakCompareAndSet() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a; a = updaterFor("x"); x = one; do {} while (!a.weakCompareAndSet(this, one, two)); do {} while (!a.weakCompareAndSet(this, two, m4)); assertSame(m4, a.get(this)); do {} while (!a.weakCompareAndSet(this, m4, seven)); assertSame(seven, a.get(this)); }
/** * getAndSet returns previous value and sets to given value */ public void testGetAndSet() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a; a = updaterFor("x"); x = one; assertSame(one, a.getAndSet(this, zero)); assertSame(zero, a.getAndSet(this, m10)); assertSame(m10, a.getAndSet(this, 1)); }
/** * AtomicReferenceFieldUpdater getAndUpdate returns previous value * and updates result of supplied function */ public void testReferenceFieldUpdaterGetAndUpdate() { AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater(); a.set(this, one); assertEquals(new Integer(1), a.getAndUpdate(this, Atomic8Test::addInteger17)); assertEquals(new Integer(18), a.getAndUpdate(this, Atomic8Test::addInteger17)); assertEquals(new Integer(35), a.get(this)); assertEquals(new Integer(35), anIntegerField); }
/** * AtomicReferenceFieldUpdater updateAndGet updates with supplied * function and returns result. */ public void testReferenceFieldUpdaterUpdateAndGet() { AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater(); a.set(this, one); assertEquals(new Integer(18), a.updateAndGet(this, Atomic8Test::addInteger17)); assertEquals(new Integer(35), a.updateAndGet(this, Atomic8Test::addInteger17)); assertEquals(new Integer(35), a.get(this)); assertEquals(new Integer(35), anIntegerField); }
/** * AtomicReferenceFieldUpdater returns previous value and updates * with supplied function. */ public void testReferenceFieldUpdaterGetAndAccumulate() { AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater(); a.set(this, one); assertEquals(new Integer(1), a.getAndAccumulate(this, 2, Atomic8Test::sumInteger)); assertEquals(new Integer(3), a.getAndAccumulate(this, 3, Atomic8Test::sumInteger)); assertEquals(new Integer(6), a.get(this)); assertEquals(new Integer(6), anIntegerField); }
/** * AtomicReferenceFieldUpdater accumulateAndGet updates with * supplied function and returns result. */ public void testReferenceFieldUpdaterAccumulateAndGet() { AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater(); a.set(this, one); assertEquals(new Integer(7), a.accumulateAndGet(this, 6, Atomic8Test::sumInteger)); assertEquals(new Integer(10), a.accumulateAndGet(this, 3, Atomic8Test::sumInteger)); assertEquals(new Integer(10), a.get(this)); assertEquals(new Integer(10), anIntegerField); }
public void checkCompareAndSetProtectedSub() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a = AtomicReferenceFieldUpdater.newUpdater (AtomicReferenceFieldUpdaterTest.class, Integer.class, "protectedField"); this.protectedField = one; assertTrue(a.compareAndSet(this, one, two)); assertTrue(a.compareAndSet(this, two, m4)); assertSame(m4, a.get(this)); assertFalse(a.compareAndSet(this, m5, seven)); assertFalse(seven == a.get(this)); assertTrue(a.compareAndSet(this, m4, seven)); assertSame(seven, a.get(this)); }
/** * compareAndSet succeeds in changing value if equal to expected else fails */ public void testCompareAndSet() { AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a; a = updaterFor("x"); x = one; assertTrue(a.compareAndSet(this, one, two)); assertTrue(a.compareAndSet(this, two, m4)); assertSame(m4, a.get(this)); assertFalse(a.compareAndSet(this, m5, seven)); assertFalse(seven == a.get(this)); assertTrue(a.compareAndSet(this, m4, seven)); assertSame(seven, a.get(this)); }
public static void main(String[] args) throws InterruptedException { final AtomicReferenceFieldUpdater<Person, String> nameFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Person.class, String.class, "name"); final AtomicIntegerFieldUpdater<Person> ageFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(Person.class, "age"); final Person person = new Person(1, "zhangsan", 20); final Random radom = new Random(); final CountDownLatch latch = new CountDownLatch(SIZE); for(int i = 0; i < SIZE; i++) { new Thread(new Runnable() { public void run() { try { TimeUnit.MICROSECONDS.sleep(radom.nextInt(1000)); if(nameFieldUpdater.compareAndSet(person, "zhangsan", "lisi")) { System.out.println(Thread.currentThread().getName() + " update field name success."); } ThreadUtils.sleepSilently(radom.nextInt(1000)); if(ageFieldUpdater.compareAndSet(person, 20, 30)) { System.out.println(Thread.currentThread().getName() + " update field age success."); } } catch(Exception e) { e.printStackTrace(); } finally { latch.countDown(); } } }, "thread"+i).start(); } latch.await(); }
/** * Create a new optimized {@link AtomicReferenceFieldUpdater} or {@code null} if it * could not be created. Because of this the caller need to check for {@code null} and if {@code null} is returned * use {@link AtomicReferenceFieldUpdater#newUpdater(Class, Class, String)} as fallback. */ public static <U, W> AtomicReferenceFieldUpdater<U, W> newAtomicReferenceFieldUpdater( Class<? super U> tclass, String fieldName) { if (hasUnsafe()) { try { return PlatformDependent0.newAtomicReferenceFieldUpdater(tclass, fieldName); } catch (Throwable ignore) { // ignore } } return null; }
/** compare raw numbers for atomic ops using JDK vs unsafe wrapper classes */ public void SW_testCompareAtomicOps() { final AtomicIntegerFieldUpdater<ConcurrentMapOpsTest> intJDKCounter = AtomicIntegerFieldUpdater.newUpdater(ConcurrentMapOpsTest.class, "intJDKCounter"); final AtomicLongFieldUpdater<ConcurrentMapOpsTest> longJDKCounter = AtomicLongFieldUpdater.newUpdater(ConcurrentMapOpsTest.class, "longJDKCounter"); final AtomicReferenceFieldUpdater<ConcurrentMapOpsTest, LongRef> refJDKCounter = AtomicReferenceFieldUpdater.newUpdater( ConcurrentMapOpsTest.class, LongRef.class, "refJDKCounter"); final AtomicIntegerFieldUpdater<ConcurrentMapOpsTest> intUnsafeCounter = AtomicUpdaterFactory.newIntegerFieldUpdater(ConcurrentMapOpsTest.class, "intUnsafeCounter"); final AtomicLongFieldUpdater<ConcurrentMapOpsTest> longUnsafeCounter = AtomicUpdaterFactory.newLongFieldUpdater(ConcurrentMapOpsTest.class, "longUnsafeCounter"); final AtomicReferenceFieldUpdater<ConcurrentMapOpsTest, LongRef> refUnsafeCounter = AtomicUpdaterFactory.newReferenceFieldUpdater( ConcurrentMapOpsTest.class, LongRef.class, "refUnsafeCounter"); // some warmups runAtomicOps(1, 50000, intJDKCounter, longJDKCounter, refJDKCounter, intUnsafeCounter, longUnsafeCounter, refUnsafeCounter); // timed runs with single threads to see the raw overheads with no // concurrency (as we would expect in most usual cases) runAtomicOps(1, 50000000, intJDKCounter, longJDKCounter, refJDKCounter, intUnsafeCounter, longUnsafeCounter, refUnsafeCounter); // now with concurrency runAtomicOps(5, 2000000, intJDKCounter, longJDKCounter, refJDKCounter, intUnsafeCounter, longUnsafeCounter, refUnsafeCounter); }
/** * Creates and returns an updater for objects with the given reference field. */ public static <T, V> AtomicReferenceFieldUpdater<T, V> newReferenceFieldUpdater( Class<T> tclass, Class<V> vclass, String fieldName) { if (UnsafeHolder.hasUnsafe()) { return new UnsafeAtomicReferenceUpdater<T, V>(tclass, vclass, fieldName); } else { return AtomicReferenceFieldUpdater.newUpdater(tclass, vclass, fieldName); } }