java.util.concurrent.atomic.AtomicReferenceArray

Here are the examples of the java api class java.util.concurrent.atomic.AtomicReferenceArray taken from open source projects.

1. AtomicReferenceArrayTest#testSerialization()

View license
/**
     * a deserialized serialized array holds same values
     */
public void testSerialization() throws Exception {
    AtomicReferenceArray x = new AtomicReferenceArray(SIZE);
    for (int i = 0; i < SIZE; i++) {
        x.set(i, new Integer(-i));
    }
    AtomicReferenceArray y = serialClone(x);
    assertNotSame(x, y);
    assertEquals(x.length(), y.length());
    for (int i = 0; i < SIZE; i++) {
        assertEquals(x.get(i), y.get(i));
    }
}

2. AtomicReferenceArrayTest#testCompareAndSetInMultipleThreads()

View license
/**
     * compareAndSet in one thread enables another waiting for value
     * to succeed
     */
public void testCompareAndSetInMultipleThreads() throws InterruptedException {
    final AtomicReferenceArray a = new AtomicReferenceArray(1);
    a.set(0, one);
    Thread t = new Thread(new CheckedRunnable() {

        public void realRun() {
            while (!a.compareAndSet(0, two, three)) Thread.yield();
        }
    });
    t.start();
    assertTrue(a.compareAndSet(0, one, two));
    t.join(LONG_DELAY_MS);
    assertFalse(t.isAlive());
    assertSame(three, a.get(0));
}

3. ConcurrentHashMap#replace()

View license
@Override
public V replace(K key, V value) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == null) {
        return null;
    }
    return this.slowReplace(key, value, hash, currentArray);
}

4. ConcurrentHashMap#get()

View license
public V get(Object key) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int index = ConcurrentHashMap.indexFor(hash, currentArray.length());
    Object o = currentArray.get(index);
    if (o == RESIZED || o == RESIZING) {
        return this.slowGet(key, hash, index, currentArray);
    }
    for (Entry<K, V> e = (Entry<K, V>) o; e != null; e = e.getNext()) {
        Object k;
        if ((k = e.key) == key || key.equals(k)) {
            return e.value;
        }
    }
    return null;
}

5. ConcurrentHashMap#put()

View license
public V put(K key, V value) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == null) {
        Entry<K, V> newEntry = new Entry<K, V>(key, value, null);
        if (currentArray.compareAndSet(index, null, newEntry)) {
            this.addToSize(1);
            return null;
        }
    }
    return this.slowPut(key, value, hash, currentArray);
}

6. ConcurrentHashMap#helpWithResize()

View license
private AtomicReferenceArray helpWithResize(AtomicReferenceArray currentArray) {
    ResizeContainer resizeContainer = (ResizeContainer) currentArray.get(currentArray.length() - 1);
    AtomicReferenceArray newTable = resizeContainer.nextArray;
    if (resizeContainer.getQueuePosition() > ResizeContainer.QUEUE_INCREMENT) {
        resizeContainer.incrementResizer();
        this.reverseTransfer(currentArray, resizeContainer);
        resizeContainer.decrementResizerAndNotify();
    }
    return newTable;
}

7. ConcurrentHashMap#helpWithResizeWhileCurrentIndex()

View license
private AtomicReferenceArray helpWithResizeWhileCurrentIndex(AtomicReferenceArray currentArray, int index) {
    AtomicReferenceArray newArray = this.helpWithResize(currentArray);
    int helpCount = 0;
    while (currentArray.get(index) != RESIZED) {
        helpCount++;
        newArray = this.helpWithResize(currentArray);
        if ((helpCount & 7) == 0) {
            Thread.yield();
        }
    }
    return newArray;
}

8. ConcurrentHashMap#updateValueWith()

View license
@Override
public <P> V updateValueWith(K key, Function0<? extends V> factory, Function2<? super V, ? super P, ? extends V> function, P parameter) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == null) {
        V result = function.value(factory.value(), parameter);
        Entry<K, V> newEntry = new Entry<>(key, result, null);
        if (currentArray.compareAndSet(index, null, newEntry)) {
            this.addToSize(1);
            return result;
        }
    }
    return this.slowUpdateValueWith(key, factory, function, parameter, hash, currentArray);
}

9. ConcurrentHashMap#updateValue()

View license
@Override
public V updateValue(K key, Function0<? extends V> factory, Function<? super V, ? extends V> function) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == null) {
        V result = function.valueOf(factory.value());
        Entry<K, V> newEntry = new Entry<>(key, result, null);
        if (currentArray.compareAndSet(index, null, newEntry)) {
            this.addToSize(1);
            return result;
        }
    }
    return this.slowUpdateValue(key, factory, function, hash, currentArray);
}

10. ConcurrentHashMap#replace()

View license
public V replace(K key, V value) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == null) {
        return null;
    }
    return this.slowReplace(key, value, hash, currentArray);
}

11. ConcurrentHashMap#hashCode()

View license
@Override
public int hashCode() {
    int h = 0;
    AtomicReferenceArray currentArray = this.table;
    for (int i = 0; i < currentArray.length() - 1; i++) {
        Object o = currentArray.get(i);
        if (o == RESIZED || o == RESIZING) {
            throw new ConcurrentModificationException("can't compute hashcode while resizing!");
        }
        Entry<K, V> e = (Entry<K, V>) o;
        while (e != null) {
            Object key = e.getKey();
            Object value = e.getValue();
            h += (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
            e = e.getNext();
        }
    }
    return h;
}

12. ConcurrentHashMap#hashCode()

View license
@Override
public int hashCode() {
    int h = 0;
    AtomicReferenceArray currentArray = this.table;
    for (int i = 0; i < currentArray.length() - 1; i++) {
        Object o = currentArray.get(i);
        if (o == RESIZED || o == RESIZING) {
            throw new ConcurrentModificationException("can't compute hashcode while resizing!");
        }
        Entry<K, V> e = (Entry<K, V>) o;
        while (e != null) {
            Object key = e.getKey();
            Object value = e.getValue();
            h += (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
            e = e.getNext();
        }
    }
    return h;
}

13. ConcurrentHashMap#put()

View license
@Override
public V put(K key, V value) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == null) {
        Entry<K, V> newEntry = new Entry<>(key, value, null);
        if (currentArray.compareAndSet(index, null, newEntry)) {
            this.addToSize(1);
            return null;
        }
    }
    return this.slowPut(key, value, hash, currentArray);
}

14. ConcurrentHashMap#get()

View license
@Override
public V get(Object key) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int index = ConcurrentHashMap.indexFor(hash, currentArray.length());
    Object o = currentArray.get(index);
    if (o == RESIZED || o == RESIZING) {
        return this.slowGet(key, hash, index, currentArray);
    }
    for (Entry<K, V> e = (Entry<K, V>) o; e != null; e = e.getNext()) {
        Object k;
        if ((k = e.key) == key || key.equals(k)) {
            return e.value;
        }
    }
    return null;
}

15. ConcurrentHashMap#updateValue()

View license
@Override
public V updateValue(K key, Function0<? extends V> factory, Function<? super V, ? extends V> function) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == null) {
        V result = function.valueOf(factory.value());
        Entry<K, V> newEntry = new Entry<K, V>(key, result, null);
        if (currentArray.compareAndSet(index, null, newEntry)) {
            this.addToSize(1);
            return result;
        }
    }
    return this.slowUpdateValue(key, factory, function, hash, currentArray);
}

16. ConcurrentHashMap#updateValueWith()

View license
@Override
public <P> V updateValueWith(K key, Function0<? extends V> factory, Function2<? super V, ? super P, ? extends V> function, P parameter) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == null) {
        V result = function.value(factory.value(), parameter);
        Entry<K, V> newEntry = new Entry<K, V>(key, result, null);
        if (currentArray.compareAndSet(index, null, newEntry)) {
            this.addToSize(1);
            return result;
        }
    }
    return this.slowUpdateValueWith(key, factory, function, parameter, hash, currentArray);
}

17. ConcurrentHashMap#helpWithResizeWhileCurrentIndex()

View license
private AtomicReferenceArray helpWithResizeWhileCurrentIndex(AtomicReferenceArray currentArray, int index) {
    AtomicReferenceArray newArray = this.helpWithResize(currentArray);
    int helpCount = 0;
    while (currentArray.get(index) != RESIZED) {
        helpCount++;
        newArray = this.helpWithResize(currentArray);
        if ((helpCount & 7) == 0) {
            Thread.yield();
        }
    }
    return newArray;
}

18. ConcurrentHashMap#helpWithResize()

View license
private AtomicReferenceArray helpWithResize(AtomicReferenceArray currentArray) {
    ResizeContainer resizeContainer = (ResizeContainer) currentArray.get(currentArray.length() - 1);
    AtomicReferenceArray newTable = resizeContainer.nextArray;
    if (resizeContainer.getQueuePosition() > ResizeContainer.QUEUE_INCREMENT) {
        resizeContainer.incrementResizer();
        this.reverseTransfer(currentArray, resizeContainer);
        resizeContainer.decrementResizerAndNotify();
    }
    return newTable;
}

19. AtomicReferenceArrayTest#testCompareAndSet()

View license
/**
     * compareAndSet succeeds in changing value if equal to expected else fails
     */
public void testCompareAndSet() {
    AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
    for (int i = 0; i < SIZE; i++) {
        aa.set(i, one);
        assertTrue(aa.compareAndSet(i, one, two));
        assertTrue(aa.compareAndSet(i, two, m4));
        assertSame(m4, aa.get(i));
        assertFalse(aa.compareAndSet(i, m5, seven));
        assertSame(m4, aa.get(i));
        assertTrue(aa.compareAndSet(i, m4, seven));
        assertSame(seven, aa.get(i));
    }
}

20. ConcurrentHashMap#remove()

View license
public boolean remove(Object key, Object value) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    //noinspection LabeledStatement
    outer: while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key) && this.nullSafeEquals(e.getValue(), value)) {
                    Entry<K, V> replacement = this.createReplacementChainForRemoval((Entry<K, V>) o, e);
                    if (currentArray.compareAndSet(index, o, replacement)) {
                        this.addToSize(-1);
                        return true;
                    }
                    //noinspection ContinueStatementWithLabel
                    continue outer;
                }
                e = e.getNext();
            }
            return false;
        }
    }
}

21. ConcurrentHashMap#containsValue()

View license
public boolean containsValue(Object value) {
    AtomicReferenceArray currentArray = this.table;
    ResizeContainer resizeContainer;
    do {
        resizeContainer = null;
        for (int i = 0; i < currentArray.length() - 1; i++) {
            Object o = currentArray.get(i);
            if (o == RESIZED || o == RESIZING) {
                resizeContainer = (ResizeContainer) currentArray.get(currentArray.length() - 1);
            } else if (o != null) {
                Entry<K, V> e = (Entry<K, V>) o;
                while (e != null) {
                    Object v = e.getValue();
                    if (this.nullSafeEquals(v, value)) {
                        return true;
                    }
                    e = e.getNext();
                }
            }
        }
        if (resizeContainer != null) {
            if (resizeContainer.isNotDone()) {
                this.helpWithResize(currentArray);
                resizeContainer.waitForAllResizers();
            }
            currentArray = resizeContainer.nextArray;
        }
    } while (resizeContainer != null);
    return false;
}

22. ConcurrentHashMap#getEntry()

View license
private Entry<K, V> getEntry(Object key) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e;
                }
                e = e.getNext();
            }
            return null;
        }
    }
}

23. AtomicReferenceArrayTest#testGetAndSet()

View license
/**
     * getAndSet returns previous value and sets to given value at given index
     */
public void testGetAndSet() {
    AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
    for (int i = 0; i < SIZE; i++) {
        aa.set(i, one);
        assertSame(one, aa.getAndSet(i, zero));
        assertSame(zero, aa.getAndSet(i, m10));
        assertSame(m10, aa.getAndSet(i, one));
    }
}

24. AtomicReferenceArrayTest#testWeakCompareAndSet()

View license
/**
     * repeated weakCompareAndSet succeeds in changing value when equal
     * to expected
     */
public void testWeakCompareAndSet() {
    AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
    for (int i = 0; i < SIZE; i++) {
        aa.set(i, one);
        do {
        } while (!aa.weakCompareAndSet(i, one, two));
        do {
        } while (!aa.weakCompareAndSet(i, two, m4));
        assertSame(m4, aa.get(i));
        do {
        } while (!aa.weakCompareAndSet(i, m4, seven));
        assertSame(seven, aa.get(i));
    }
}

25. ConcurrentHashMap#clear()

View license
public void clear() {
    AtomicReferenceArray currentArray = this.table;
    ResizeContainer resizeContainer;
    do {
        resizeContainer = null;
        for (int i = 0; i < currentArray.length() - 1; i++) {
            Object o = currentArray.get(i);
            if (o == RESIZED || o == RESIZING) {
                resizeContainer = (ResizeContainer) currentArray.get(currentArray.length() - 1);
            } else if (o != null) {
                Entry<K, V> e = (Entry<K, V>) o;
                if (currentArray.compareAndSet(i, o, null)) {
                    int removedEntries = 0;
                    while (e != null) {
                        removedEntries++;
                        e = e.getNext();
                    }
                    this.addToSize(-removedEntries);
                }
            }
        }
        if (resizeContainer != null) {
            if (resizeContainer.isNotDone()) {
                this.helpWithResize(currentArray);
                resizeContainer.waitForAllResizers();
            }
            currentArray = resizeContainer.nextArray;
        }
    } while (resizeContainer != null);
}

26. ConcurrentHashMap#replace()

View license
public boolean replace(K key, V oldValue, V newValue) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == RESIZED || o == RESIZING) {
        return this.slowReplace(key, oldValue, newValue, hash, currentArray);
    }
    Entry<K, V> e = (Entry<K, V>) o;
    while (e != null) {
        Object candidate = e.getKey();
        if (candidate == key || candidate.equals(key)) {
            if (oldValue == e.getValue() || (oldValue != null && oldValue.equals(e.getValue()))) {
                Entry<K, V> replacement = this.createReplacementChainForRemoval((Entry<K, V>) o, e);
                Entry<K, V> newEntry = new Entry<K, V>(key, newValue, replacement);
                return currentArray.compareAndSet(index, o, newEntry) || this.slowReplace(key, oldValue, newValue, hash, currentArray);
            }
            return false;
        }
        e = e.getNext();
    }
    return false;
}

27. AtomicReferenceArrayTest#testGetLazySet()

View license
/**
     * get returns the last value lazySet at index by same thread
     */
public void testGetLazySet() {
    AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
    for (int i = 0; i < SIZE; i++) {
        aa.lazySet(i, one);
        assertSame(one, aa.get(i));
        aa.lazySet(i, two);
        assertSame(two, aa.get(i));
        aa.lazySet(i, m3);
        assertSame(m3, aa.get(i));
    }
}

28. AtomicReferenceArrayTest#testGetSet()

View license
/**
     * get returns the last value set at index
     */
public void testGetSet() {
    AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
    for (int i = 0; i < SIZE; i++) {
        aa.set(i, one);
        assertSame(one, aa.get(i));
        aa.set(i, two);
        assertSame(two, aa.get(i));
        aa.set(i, m3);
        assertSame(m3, aa.get(i));
    }
}

29. GridCacheIncrementTransformTest#beforeTest()

View license
@Override
protected void beforeTest() throws Exception {
    startGrids(GRID_CNT);
    grids = new AtomicReferenceArray<>(GRID_CNT);
    for (int i = 0; i < GRID_CNT; i++) grids.set(i, grid(i));
    jcache(0).put("key", new TestObject(0));
}

30. ConcurrentHashMap#remove()

View license
public V remove(Object key) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == RESIZED || o == RESIZING) {
        return this.slowRemove(key, hash, currentArray);
    }
    Entry<K, V> e = (Entry<K, V>) o;
    while (e != null) {
        Object candidate = e.getKey();
        if (candidate.equals(key)) {
            Entry<K, V> replacement = this.createReplacementChainForRemoval((Entry<K, V>) o, e);
            if (currentArray.compareAndSet(index, o, replacement)) {
                this.addToSize(-1);
                return e.getValue();
            }
            return this.slowRemove(key, hash, currentArray);
        }
        e = e.getNext();
    }
    return null;
}

31. ConcurrentHashMap#parallelForEachKeyValue()

View license
public void parallelForEachKeyValue(List<Procedure2<K, V>> blocks, Executor executor) {
    final AtomicReferenceArray currentArray = this.table;
    int chunks = blocks.size();
    if (chunks > 1) {
        FutureTask<?>[] futures = new FutureTask<?>[chunks];
        int chunkSize = currentArray.length() / chunks;
        if (currentArray.length() % chunks != 0) {
            chunkSize++;
        }
        for (int i = 0; i < chunks; i++) {
            final int start = i * chunkSize;
            final int end = Math.min((i + 1) * chunkSize, currentArray.length());
            final Procedure2<K, V> block = blocks.get(i);
            futures[i] = new FutureTask(new Runnable() {

                public void run() {
                    ConcurrentHashMap.this.sequentialForEachKeyValue(block, currentArray, start, end);
                }
            }, null);
            executor.execute(futures[i]);
        }
        for (int i = 0; i < chunks; i++) {
            try {
                futures[i].get();
            } catch (Exception e) {
                throw new RuntimeException("parallelForEachKeyValue failed", e);
            }
        }
    } else {
        this.sequentialForEachKeyValue(blocks.get(0), currentArray, 0, currentArray.length());
    }
}

32. ConcurrentHashMap#parallelForEachValue()

View license
public void parallelForEachValue(List<Procedure<V>> blocks, Executor executor) {
    final AtomicReferenceArray currentArray = this.table;
    int chunks = blocks.size();
    if (chunks > 1) {
        FutureTask<?>[] futures = new FutureTask<?>[chunks];
        int chunkSize = currentArray.length() / chunks;
        if (currentArray.length() % chunks != 0) {
            chunkSize++;
        }
        for (int i = 0; i < chunks; i++) {
            final int start = i * chunkSize;
            final int end = Math.min((i + 1) * chunkSize, currentArray.length() - 1);
            final Procedure<V> block = blocks.get(i);
            futures[i] = new FutureTask(new Runnable() {

                public void run() {
                    ConcurrentHashMap.this.sequentialForEachValue(block, currentArray, start, end);
                }
            }, null);
            executor.execute(futures[i]);
        }
        for (int i = 0; i < chunks; i++) {
            try {
                futures[i].get();
            } catch (Exception e) {
                throw new RuntimeException("parallelForEachKeyValue failed", e);
            }
        }
    } else {
        this.sequentialForEachValue(blocks.get(0), currentArray, 0, currentArray.length());
    }
}

33. ConcurrentHashMap#transfer()

View license
/*
     * Transfer all entries from src to dest tables
     */
private void transfer(AtomicReferenceArray src, ResizeContainer resizeContainer) {
    AtomicReferenceArray dest = resizeContainer.nextArray;
    for (int j = 0; j < src.length() - 1; ) {
        Object o = src.get(j);
        if (o == null) {
            if (src.compareAndSet(j, null, RESIZED)) {
                j++;
            }
        } else if (o == RESIZED || o == RESIZING) {
            j = (j & ~(ResizeContainer.QUEUE_INCREMENT - 1)) + ResizeContainer.QUEUE_INCREMENT;
            if (resizeContainer.resizers.get() == 1) {
                break;
            }
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            if (src.compareAndSet(j, o, RESIZING)) {
                while (e != null) {
                    this.unconditionalCopy(dest, e);
                    e = e.getNext();
                }
                src.set(j, RESIZED);
                j++;
            }
        }
    }
    resizeContainer.decrementResizerAndNotify();
    resizeContainer.waitForAllResizers();
}

34. ConcurrentHashMap#getIfAbsentPutWith()

View license
@Override
public <P> V getIfAbsentPutWith(K key, Function<? super P, ? extends V> function, P parameter) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    V newValue = null;
    boolean createdValue = false;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e.getValue();
                }
                e = e.getNext();
            }
            if (!createdValue) {
                createdValue = true;
                newValue = function.valueOf(parameter);
            }
            Entry<K, V> newEntry = new Entry<K, V>(key, newValue, (Entry<K, V>) o);
            if (currentArray.compareAndSet(index, o, newEntry)) {
                this.incrementSizeAndPossiblyResize(currentArray, length, o);
                return newValue;
            }
        }
    }
}

35. ConcurrentHashMap#replace()

View license
@Override
public boolean replace(K key, V oldValue, V newValue) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == RESIZED || o == RESIZING) {
        return this.slowReplace(key, oldValue, newValue, hash, currentArray);
    }
    Entry<K, V> e = (Entry<K, V>) o;
    while (e != null) {
        Object candidate = e.getKey();
        if (candidate == key || candidate.equals(key)) {
            if (oldValue == e.getValue() || (oldValue != null && oldValue.equals(e.getValue()))) {
                Entry<K, V> replacement = this.createReplacementChainForRemoval((Entry<K, V>) o, e);
                Entry<K, V> newEntry = new Entry<>(key, newValue, replacement);
                return currentArray.compareAndSet(index, o, newEntry) || this.slowReplace(key, oldValue, newValue, hash, currentArray);
            }
            return false;
        }
        e = e.getNext();
    }
    return false;
}

36. ConcurrentHashMap#putIfAbsent()

View license
@Override
public V putIfAbsent(K key, V value) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                K candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e.getValue();
                }
                e = e.getNext();
            }
            Entry<K, V> newEntry = new Entry<>(key, value, (Entry<K, V>) o);
            if (currentArray.compareAndSet(index, o, newEntry)) {
                this.incrementSizeAndPossiblyResize(currentArray, length, o);
                // per the contract of putIfAbsent, we return null when the map didn't have this key before
                return null;
            }
        }
    }
}

37. ConcurrentHashMap#transfer()

View license
/*
     * Transfer all entries from src to dest tables
     */
private void transfer(AtomicReferenceArray src, ResizeContainer resizeContainer) {
    AtomicReferenceArray dest = resizeContainer.nextArray;
    for (int j = 0; j < src.length() - 1; ) {
        Object o = src.get(j);
        if (o == null) {
            if (src.compareAndSet(j, null, RESIZED)) {
                j++;
            }
        } else if (o == RESIZED || o == RESIZING) {
            j = (j & ~(ResizeContainer.QUEUE_INCREMENT - 1)) + ResizeContainer.QUEUE_INCREMENT;
            if (resizeContainer.resizers.get() == 1) {
                break;
            }
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            if (src.compareAndSet(j, o, RESIZING)) {
                while (e != null) {
                    this.unconditionalCopy(dest, e);
                    e = e.getNext();
                }
                src.set(j, RESIZED);
                j++;
            }
        }
    }
    resizeContainer.decrementResizerAndNotify();
    resizeContainer.waitForAllResizers();
}

38. ConcurrentHashMap#reverseTransfer()

View license
private void reverseTransfer(AtomicReferenceArray src, ResizeContainer resizeContainer) {
    AtomicReferenceArray dest = resizeContainer.nextArray;
    while (resizeContainer.getQueuePosition() > 0) {
        int start = resizeContainer.subtractAndGetQueuePosition();
        int end = start + ResizeContainer.QUEUE_INCREMENT;
        if (end > 0) {
            if (start < 0) {
                start = 0;
            }
            for (int j = end - 1; j >= start; ) {
                Object o = src.get(j);
                if (o == null) {
                    if (src.compareAndSet(j, null, RESIZED)) {
                        j--;
                    }
                } else if (o == RESIZED || o == RESIZING) {
                    resizeContainer.zeroOutQueuePosition();
                    return;
                } else {
                    Entry<K, V> e = (Entry<K, V>) o;
                    if (src.compareAndSet(j, o, RESIZING)) {
                        while (e != null) {
                            this.unconditionalCopy(dest, e);
                            e = e.getNext();
                        }
                        src.set(j, RESIZED);
                        j--;
                    }
                }
            }
        }
    }
}

39. ConcurrentHashMap#unconditionalCopy()

View license
private void unconditionalCopy(AtomicReferenceArray dest, Entry<K, V> toCopyEntry) {
    int hash = this.hash(toCopyEntry.getKey());
    AtomicReferenceArray currentArray = dest;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = ((ResizeContainer) currentArray.get(length - 1)).nextArray;
        } else {
            Entry<K, V> newEntry;
            if (o == null) {
                if (toCopyEntry.getNext() == null) {
                    // no need to duplicate
                    newEntry = toCopyEntry;
                } else {
                    newEntry = new Entry<>(toCopyEntry.getKey(), toCopyEntry.getValue());
                }
            } else {
                newEntry = new Entry<>(toCopyEntry.getKey(), toCopyEntry.getValue(), (Entry<K, V>) o);
            }
            if (currentArray.compareAndSet(index, o, newEntry)) {
                return;
            }
        }
    }
}

40. ConcurrentHashMap#getIfAbsentPut()

View license
@Override
public V getIfAbsentPut(K key, Function0<? extends V> factory) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    V newValue = null;
    boolean createdValue = false;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e.getValue();
                }
                e = e.getNext();
            }
            if (!createdValue) {
                createdValue = true;
                newValue = factory.value();
            }
            Entry<K, V> newEntry = new Entry<>(key, newValue, (Entry<K, V>) o);
            if (currentArray.compareAndSet(index, o, newEntry)) {
                this.incrementSizeAndPossiblyResize(currentArray, length, o);
                return newValue;
            }
        }
    }
}

41. ConcurrentHashMap#getIfAbsentPut()

View license
@Override
public V getIfAbsentPut(K key, V value) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e.getValue();
                }
                e = e.getNext();
            }
            Entry<K, V> newEntry = new Entry<>(key, value, (Entry<K, V>) o);
            if (currentArray.compareAndSet(index, o, newEntry)) {
                this.incrementSizeAndPossiblyResize(currentArray, length, o);
                return value;
            }
        }
    }
}

42. ConcurrentHashMap#putIfAbsentGetIfPresent()

View license
/**
     * It puts an object into the map based on the key. It uses a copy of the key converted by transformer.
     *
     * @param key            The "mutable" key, which has the same identity/hashcode as the inserted key, only during this call
     * @param keyTransformer If the record is absent, the transformer will transform the "mutable" key into an immutable copy of the key.
     *                       Note that the transformed key must have the same identity/hashcode as the original "mutable" key.
     * @param factory        It creates an object, if it is not present in the map already.
     */
public <P1, P2> V putIfAbsentGetIfPresent(K key, Function2<K, V, K> keyTransformer, Function3<P1, P2, K, V> factory, P1 param1, P2 param2) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    V newValue = null;
    boolean createdValue = false;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e.getValue();
                }
                e = e.getNext();
            }
            if (!createdValue) {
                createdValue = true;
                newValue = factory.value(param1, param2, key);
                if (newValue == null) {
                    // null value means no mapping is required
                    return null;
                }
                key = keyTransformer.value(key, newValue);
            }
            Entry<K, V> newEntry = new Entry<>(key, newValue, (Entry<K, V>) o);
            if (currentArray.compareAndSet(index, o, newEntry)) {
                this.incrementSizeAndPossiblyResize(currentArray, length, o);
                return null;
            }
        }
    }
}

43. ConcurrentHashMap#remove()

View license
@Override
public boolean remove(Object key, Object value) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    //noinspection LabeledStatement
    outer: while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key) && this.nullSafeEquals(e.getValue(), value)) {
                    Entry<K, V> replacement = this.createReplacementChainForRemoval((Entry<K, V>) o, e);
                    if (currentArray.compareAndSet(index, o, replacement)) {
                        this.addToSize(-1);
                        return true;
                    }
                    //noinspection ContinueStatementWithLabel
                    continue outer;
                }
                e = e.getNext();
            }
            return false;
        }
    }
}

44. ConcurrentHashMap#containsValue()

View license
@Override
public boolean containsValue(Object value) {
    AtomicReferenceArray currentArray = this.table;
    ResizeContainer resizeContainer;
    do {
        resizeContainer = null;
        for (int i = 0; i < currentArray.length() - 1; i++) {
            Object o = currentArray.get(i);
            if (o == RESIZED || o == RESIZING) {
                resizeContainer = (ResizeContainer) currentArray.get(currentArray.length() - 1);
            } else if (o != null) {
                Entry<K, V> e = (Entry<K, V>) o;
                while (e != null) {
                    Object v = e.getValue();
                    if (this.nullSafeEquals(v, value)) {
                        return true;
                    }
                    e = e.getNext();
                }
            }
        }
        if (resizeContainer != null) {
            if (resizeContainer.isNotDone()) {
                this.helpWithResize(currentArray);
                resizeContainer.waitForAllResizers();
            }
            currentArray = resizeContainer.nextArray;
        }
    } while (resizeContainer != null);
    return false;
}

45. ConcurrentHashMap#getEntry()

View license
private Entry<K, V> getEntry(Object key) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e;
                }
                e = e.getNext();
            }
            return null;
        }
    }
}

46. ConcurrentHashMap#clear()

View license
@Override
public void clear() {
    AtomicReferenceArray currentArray = this.table;
    ResizeContainer resizeContainer;
    do {
        resizeContainer = null;
        for (int i = 0; i < currentArray.length() - 1; i++) {
            Object o = currentArray.get(i);
            if (o == RESIZED || o == RESIZING) {
                resizeContainer = (ResizeContainer) currentArray.get(currentArray.length() - 1);
            } else if (o != null) {
                Entry<K, V> e = (Entry<K, V>) o;
                if (currentArray.compareAndSet(i, o, null)) {
                    int removedEntries = 0;
                    while (e != null) {
                        removedEntries++;
                        e = e.getNext();
                    }
                    this.addToSize(-removedEntries);
                }
            }
        }
        if (resizeContainer != null) {
            if (resizeContainer.isNotDone()) {
                this.helpWithResize(currentArray);
                resizeContainer.waitForAllResizers();
            }
            currentArray = resizeContainer.nextArray;
        }
    } while (resizeContainer != null);
}

47. ConcurrentHashMap#putIfAbsentGetIfPresent()

View license
/**
     * It puts an object into the map based on the key. It uses a copy of the key converted by transformer.
     *
     * @param key            The "mutable" key, which has the same identity/hashcode as the inserted key, only during this call
     * @param keyTransformer If the record is absent, the transformer will transform the "mutable" key into an immutable copy of the key.
     *                       Note that the transformed key must have the same identity/hashcode as the original "mutable" key.
     * @param factory        It creates an object, if it is not present in the map already.
     */
public <P1, P2> V putIfAbsentGetIfPresent(K key, Function2<K, V, K> keyTransformer, Function3<P1, P2, K, V> factory, P1 param1, P2 param2) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    V newValue = null;
    boolean createdValue = false;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e.getValue();
                }
                e = e.getNext();
            }
            if (!createdValue) {
                createdValue = true;
                newValue = factory.value(param1, param2, key);
                if (newValue == null) {
                    // null value means no mapping is required
                    return null;
                }
                key = keyTransformer.value(key, newValue);
            }
            Entry<K, V> newEntry = new Entry<K, V>(key, newValue, (Entry<K, V>) o);
            if (currentArray.compareAndSet(index, o, newEntry)) {
                this.incrementSizeAndPossiblyResize(currentArray, length, o);
                return null;
            }
        }
    }
}

48. ConcurrentHashMap#remove()

View license
@Override
public V remove(Object key) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    int length = currentArray.length();
    int index = ConcurrentHashMap.indexFor(hash, length);
    Object o = currentArray.get(index);
    if (o == RESIZED || o == RESIZING) {
        return this.slowRemove(key, hash, currentArray);
    }
    Entry<K, V> e = (Entry<K, V>) o;
    while (e != null) {
        Object candidate = e.getKey();
        if (candidate.equals(key)) {
            Entry<K, V> replacement = this.createReplacementChainForRemoval((Entry<K, V>) o, e);
            if (currentArray.compareAndSet(index, o, replacement)) {
                this.addToSize(-1);
                return e.getValue();
            }
            return this.slowRemove(key, hash, currentArray);
        }
        e = e.getNext();
    }
    return null;
}

49. ConcurrentHashMap#parallelForEachKeyValue()

View license
public void parallelForEachKeyValue(List<Procedure2<K, V>> blocks, Executor executor) {
    AtomicReferenceArray currentArray = this.table;
    int chunks = blocks.size();
    if (chunks > 1) {
        FutureTask<?>[] futures = new FutureTask<?>[chunks];
        int chunkSize = currentArray.length() / chunks;
        if (currentArray.length() % chunks != 0) {
            chunkSize++;
        }
        for (int i = 0; i < chunks; i++) {
            int start = i * chunkSize;
            int end = Math.min((i + 1) * chunkSize, currentArray.length());
            Procedure2<K, V> block = blocks.get(i);
            futures[i] = new FutureTask(() -> this.sequentialForEachKeyValue(block, currentArray, start, end), null);
            executor.execute(futures[i]);
        }
        for (int i = 0; i < chunks; i++) {
            try {
                futures[i].get();
            } catch (Exception e) {
                throw new RuntimeException("parallelForEachKeyValue failed", e);
            }
        }
    } else {
        this.sequentialForEachKeyValue(blocks.get(0), currentArray, 0, currentArray.length());
    }
}

50. ConcurrentHashMap#parallelForEachValue()

View license
public void parallelForEachValue(List<Procedure<V>> blocks, Executor executor) {
    AtomicReferenceArray currentArray = this.table;
    int chunks = blocks.size();
    if (chunks > 1) {
        FutureTask<?>[] futures = new FutureTask<?>[chunks];
        int chunkSize = currentArray.length() / chunks;
        if (currentArray.length() % chunks != 0) {
            chunkSize++;
        }
        for (int i = 0; i < chunks; i++) {
            int start = i * chunkSize;
            int end = Math.min((i + 1) * chunkSize, currentArray.length() - 1);
            Procedure<V> block = blocks.get(i);
            futures[i] = new FutureTask(() -> this.sequentialForEachValue(block, currentArray, start, end), null);
            executor.execute(futures[i]);
        }
        for (int i = 0; i < chunks; i++) {
            try {
                futures[i].get();
            } catch (Exception e) {
                throw new RuntimeException("parallelForEachKeyValue failed", e);
            }
        }
    } else {
        this.sequentialForEachValue(blocks.get(0), currentArray, 0, currentArray.length());
    }
}

51. ConcurrentHashMap#getIfAbsentPutWith()

View license
@Override
public <P> V getIfAbsentPutWith(K key, Function<? super P, ? extends V> function, P parameter) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    V newValue = null;
    boolean createdValue = false;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e.getValue();
                }
                e = e.getNext();
            }
            if (!createdValue) {
                createdValue = true;
                newValue = function.valueOf(parameter);
            }
            Entry<K, V> newEntry = new Entry<>(key, newValue, (Entry<K, V>) o);
            if (currentArray.compareAndSet(index, o, newEntry)) {
                this.incrementSizeAndPossiblyResize(currentArray, length, o);
                return newValue;
            }
        }
    }
}

52. CacheTests#testComputeIfAbsentCallsOnce()

Project: elasticsearch
Source File: CacheTests.java
View license
public void testComputeIfAbsentCallsOnce() throws BrokenBarrierException, InterruptedException {
    int numberOfThreads = randomIntBetween(2, 32);
    final Cache<Integer, String> cache = CacheBuilder.<Integer, String>builder().build();
    AtomicReferenceArray flags = new AtomicReferenceArray(numberOfEntries);
    for (int j = 0; j < numberOfEntries; j++) {
        flags.set(j, false);
    }
    CopyOnWriteArrayList<ExecutionException> failures = new CopyOnWriteArrayList<>();
    CyclicBarrier barrier = new CyclicBarrier(1 + numberOfThreads);
    for (int i = 0; i < numberOfThreads; i++) {
        Thread thread = new Thread(() -> {
            try {
                barrier.await();
                for (int j = 0; j < numberOfEntries; j++) {
                    try {
                        cache.computeIfAbsent(j,  key -> {
                            assertTrue(flags.compareAndSet(key, false, true));
                            return Integer.toString(key);
                        });
                    } catch (ExecutionException e) {
                        failures.add(e);
                        break;
                    }
                }
                barrier.await();
            } catch (BrokenBarrierExceptionInterruptedException |  e) {
                throw new AssertionError(e);
            }
        });
        thread.start();
    }
    // wait for all threads to be ready
    barrier.await();
    // wait for all threads to finish
    barrier.await();
    assertThat(failures, is(empty()));
}

53. ConcurrentHashMap#putIfAbsent()

View license
public V putIfAbsent(K key, V value) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                K candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e.getValue();
                }
                e = e.getNext();
            }
            Entry<K, V> newEntry = new Entry<K, V>(key, value, (Entry<K, V>) o);
            if (currentArray.compareAndSet(index, o, newEntry)) {
                this.incrementSizeAndPossiblyResize(currentArray, length, o);
                // per the contract of putIfAbsent, we return null when the map didn't have this key before
                return null;
            }
        }
    }
}

54. ReplicatedChronicleMap#initOwnTransients()

View license
private void initOwnTransients() {
    //noinspection unchecked
    assignedModificationIterators = new ReplicatedChronicleMap.ModificationIterator[0];
    modificationIterators = new AtomicReferenceArray<>(128);
    closeables = new CopyOnWriteArraySet<>();
    tierModIterFrame = new SingleThreadedFlatBitSetFrame(computeTierModIterBitSetSizeInBits());
    remoteNodeCouldBootstrapFrom = new long[128];
}

55. ConcurrentHashMap#reverseTransfer()

View license
private void reverseTransfer(AtomicReferenceArray src, ResizeContainer resizeContainer) {
    AtomicReferenceArray dest = resizeContainer.nextArray;
    while (resizeContainer.getQueuePosition() > 0) {
        int start = resizeContainer.subtractAndGetQueuePosition();
        int end = start + ResizeContainer.QUEUE_INCREMENT;
        if (end > 0) {
            if (start < 0) {
                start = 0;
            }
            for (int j = end - 1; j >= start; ) {
                Object o = src.get(j);
                if (o == null) {
                    if (src.compareAndSet(j, null, RESIZED)) {
                        j--;
                    }
                } else if (o == RESIZED || o == RESIZING) {
                    resizeContainer.zeroOutQueuePosition();
                    return;
                } else {
                    Entry<K, V> e = (Entry<K, V>) o;
                    if (src.compareAndSet(j, o, RESIZING)) {
                        while (e != null) {
                            this.unconditionalCopy(dest, e);
                            e = e.getNext();
                        }
                        src.set(j, RESIZED);
                        j--;
                    }
                }
            }
        }
    }
}

56. ConcurrentHashMap#unconditionalCopy()

View license
private void unconditionalCopy(AtomicReferenceArray dest, Entry<K, V> toCopyEntry) {
    int hash = this.hash(toCopyEntry.getKey());
    AtomicReferenceArray currentArray = dest;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = ((ResizeContainer) currentArray.get(length - 1)).nextArray;
        } else {
            Entry<K, V> newEntry;
            if (o == null) {
                if (toCopyEntry.getNext() == null) {
                    // no need to duplicate
                    newEntry = toCopyEntry;
                } else {
                    newEntry = new Entry<K, V>(toCopyEntry.getKey(), toCopyEntry.getValue());
                }
            } else {
                newEntry = new Entry<K, V>(toCopyEntry.getKey(), toCopyEntry.getValue(), (Entry<K, V>) o);
            }
            if (currentArray.compareAndSet(index, o, newEntry)) {
                return;
            }
        }
    }
}

57. ConcurrentHashMap#getIfAbsentPut()

View license
@Override
public V getIfAbsentPut(K key, Function0<? extends V> factory) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    V newValue = null;
    boolean createdValue = false;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e.getValue();
                }
                e = e.getNext();
            }
            if (!createdValue) {
                createdValue = true;
                newValue = factory.value();
            }
            Entry<K, V> newEntry = new Entry<K, V>(key, newValue, (Entry<K, V>) o);
            if (currentArray.compareAndSet(index, o, newEntry)) {
                this.incrementSizeAndPossiblyResize(currentArray, length, o);
                return newValue;
            }
        }
    }
}

58. ConcurrentHashMap#getIfAbsentPut()

View license
@Override
public V getIfAbsentPut(K key, V value) {
    int hash = this.hash(key);
    AtomicReferenceArray currentArray = this.table;
    while (true) {
        int length = currentArray.length();
        int index = ConcurrentHashMap.indexFor(hash, length);
        Object o = currentArray.get(index);
        if (o == RESIZED || o == RESIZING) {
            currentArray = this.helpWithResizeWhileCurrentIndex(currentArray, index);
        } else {
            Entry<K, V> e = (Entry<K, V>) o;
            while (e != null) {
                Object candidate = e.getKey();
                if (candidate.equals(key)) {
                    return e.getValue();
                }
                e = e.getNext();
            }
            Entry<K, V> newEntry = new Entry<K, V>(key, value, (Entry<K, V>) o);
            if (currentArray.compareAndSet(index, o, newEntry)) {
                this.incrementSizeAndPossiblyResize(currentArray, length, o);
                return value;
            }
        }
    }
}