use of java.util.concurrent.atomic.AtomicReferenceArray in project gocd by gocd.
the class ConcurrentHashMapV8 method internalCompute.
/** Implementation for compute */
@SuppressWarnings("unchecked")
private final Object internalCompute(K k, boolean onlyIfPresent, BiFun<? super K, ? super V, ? extends V> mf) {
int h = spread(k.hashCode());
Object val = null;
int delta = 0;
int count = 0;
for (AtomicReferenceArray<Node> tab = table; ; ) {
Node f;
int i, fh;
Object fk;
if (tab == null)
tab = initTable();
else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) {
if (onlyIfPresent)
break;
Node node = new Node(fh = h | LOCKED, k, null, null);
if (casTabAt(tab, i, null, node)) {
try {
count = 1;
if ((val = mf.apply(k, null)) != null) {
node.val = val;
delta = 1;
}
} finally {
if (delta == 0)
setTabAt(tab, i, null);
if (!node.casHash(fh, h)) {
node.hash = h;
synchronized (node) {
node.notifyAll();
}
;
}
}
}
if (count != 0)
break;
} else if ((fh = f.hash) == MOVED) {
if ((fk = f.key) instanceof TreeBin) {
TreeBin t = (TreeBin) fk;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
count = 1;
TreeNode p = t.getTreeNode(h, k, t.root);
Object pv;
if (p == null) {
if (onlyIfPresent)
break;
pv = null;
} else
pv = p.val;
if ((val = mf.apply(k, (V) pv)) != null) {
if (p != null)
p.val = val;
else {
count = 2;
delta = 1;
t.putTreeNode(h, k, val);
}
} else if (p != null) {
delta = -1;
t.deleteTreeNode(p);
}
}
} finally {
t.release(0);
}
if (count != 0)
break;
} else
tab = (AtomicReferenceArray<Node>) fk;
} else if ((fh & LOCKED) != 0) {
checkForResize();
f.tryAwaitLock(tab, i);
} else if (f.casHash(fh, fh | LOCKED)) {
try {
if (tabAt(tab, i) == f) {
count = 1;
for (Node e = f, pred = null; ; ++count) {
Object ek, ev;
if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) {
val = mf.apply(k, (V) ev);
if (val != null)
e.val = val;
else {
delta = -1;
Node en = e.next;
if (pred != null)
pred.next = en;
else
setTabAt(tab, i, en);
}
break;
}
pred = e;
if ((e = e.next) == null) {
if (!onlyIfPresent && (val = mf.apply(k, null)) != null) {
pred.next = new Node(h, k, val, null);
delta = 1;
if (count >= TREE_THRESHOLD)
replaceWithTreeBin(tab, i, k);
}
break;
}
}
}
} finally {
if (!f.casHash(fh | LOCKED, fh)) {
f.hash = fh;
synchronized (f) {
f.notifyAll();
}
;
}
}
if (count != 0) {
if (tab.length() <= 64)
count = 2;
break;
}
}
}
if (delta != 0) {
counter.add((long) delta);
if (count > 1)
checkForResize();
}
return val;
}
use of java.util.concurrent.atomic.AtomicReferenceArray in project gocd by gocd.
the class ConcurrentHashMapV8 method internalPutIfAbsent.
/** Implementation for putIfAbsent */
private final Object internalPutIfAbsent(Object k, Object v) {
int h = spread(k.hashCode());
int count = 0;
for (AtomicReferenceArray<Node> tab = table; ; ) {
int i;
Node f;
int fh;
Object fk, fv;
if (tab == null)
tab = initTable();
else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) {
if (casTabAt(tab, i, null, new Node(h, k, v, null)))
break;
} else if ((fh = f.hash) == MOVED) {
if ((fk = f.key) instanceof TreeBin) {
TreeBin t = (TreeBin) fk;
Object oldVal = null;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
count = 2;
TreeNode p = t.putTreeNode(h, k, v);
if (p != null)
oldVal = p.val;
}
} finally {
t.release(0);
}
if (count != 0) {
if (oldVal != null)
return oldVal;
break;
}
} else
tab = (AtomicReferenceArray<Node>) fk;
} else if ((fh & HASH_BITS) == h && (fv = f.val) != null && ((fk = f.key) == k || k.equals(fk)))
return fv;
else {
Node g = f.next;
if (g != null) {
// at least 2 nodes -- search and maybe resize
for (Node e = g; ; ) {
Object ek, ev;
if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek)))
return ev;
if ((e = e.next) == null) {
checkForResize();
break;
}
}
}
if (((fh = f.hash) & LOCKED) != 0) {
checkForResize();
f.tryAwaitLock(tab, i);
} else if (tabAt(tab, i) == f && f.casHash(fh, fh | LOCKED)) {
Object oldVal = null;
try {
if (tabAt(tab, i) == f) {
count = 1;
for (Node e = f; ; ++count) {
Object ek, ev;
if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) {
oldVal = ev;
break;
}
Node last = e;
if ((e = e.next) == null) {
last.next = new Node(h, k, v, null);
if (count >= TREE_THRESHOLD)
replaceWithTreeBin(tab, i, k);
break;
}
}
}
} finally {
if (!f.casHash(fh | LOCKED, fh)) {
f.hash = fh;
synchronized (f) {
f.notifyAll();
}
;
}
}
if (count != 0) {
if (oldVal != null)
return oldVal;
if (tab.length() <= 64)
count = 2;
break;
}
}
}
}
counter.add(1L);
if (count > 1)
checkForResize();
return null;
}
use of java.util.concurrent.atomic.AtomicReferenceArray in project gocd by gocd.
the class ConcurrentHashMapV8 method internalMerge.
/** Implementation for merge */
@SuppressWarnings("unchecked")
private final Object internalMerge(K k, V v, BiFun<? super V, ? super V, ? extends V> mf) {
int h = spread(k.hashCode());
Object val = null;
int delta = 0;
int count = 0;
for (AtomicReferenceArray<Node> tab = table; ; ) {
int i;
Node f;
int fh;
Object fk, fv;
if (tab == null)
tab = initTable();
else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) {
if (casTabAt(tab, i, null, new Node(h, k, v, null))) {
delta = 1;
val = v;
break;
}
} else if ((fh = f.hash) == MOVED) {
if ((fk = f.key) instanceof TreeBin) {
TreeBin t = (TreeBin) fk;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
count = 1;
TreeNode p = t.getTreeNode(h, k, t.root);
val = (p == null) ? v : mf.apply((V) p.val, v);
if (val != null) {
if (p != null)
p.val = val;
else {
count = 2;
delta = 1;
t.putTreeNode(h, k, val);
}
} else if (p != null) {
delta = -1;
t.deleteTreeNode(p);
}
}
} finally {
t.release(0);
}
if (count != 0)
break;
} else
tab = (AtomicReferenceArray<Node>) fk;
} else if ((fh & LOCKED) != 0) {
checkForResize();
f.tryAwaitLock(tab, i);
} else if (f.casHash(fh, fh | LOCKED)) {
try {
if (tabAt(tab, i) == f) {
count = 1;
for (Node e = f, pred = null; ; ++count) {
Object ek, ev;
if ((e.hash & HASH_BITS) == h && (ev = e.val) != null && ((ek = e.key) == k || k.equals(ek))) {
val = mf.apply((V) ev, v);
if (val != null)
e.val = val;
else {
delta = -1;
Node en = e.next;
if (pred != null)
pred.next = en;
else
setTabAt(tab, i, en);
}
break;
}
pred = e;
if ((e = e.next) == null) {
val = v;
pred.next = new Node(h, k, val, null);
delta = 1;
if (count >= TREE_THRESHOLD)
replaceWithTreeBin(tab, i, k);
break;
}
}
}
} finally {
if (!f.casHash(fh | LOCKED, fh)) {
f.hash = fh;
synchronized (f) {
f.notifyAll();
}
;
}
}
if (count != 0) {
if (tab.length() <= 64)
count = 2;
break;
}
}
}
if (delta != 0) {
counter.add((long) delta);
if (count > 1)
checkForResize();
}
return val;
}
use of java.util.concurrent.atomic.AtomicReferenceArray in project guava by google.
the class CacheLoadingTest method doConcurrentGet.
/**
* Test-helper method that performs {@code nThreads} concurrent calls to {@code cache.get(key)}
* or {@code cache.getUnchecked(key)}, and returns a List containing each of the results. The
* result for any given call to {@code cache.get} or {@code cache.getUnchecked} is the value
* returned, or the exception thrown.
*
* <p>As we iterate from {@code 0} to {@code nThreads}, threads with an even index will call
* {@code getUnchecked}, and threads with an odd index will call {@code get}. If the cache throws
* exceptions, this difference may be visible in the returned List.
*/
private static <K> List<Object> doConcurrentGet(final LoadingCache<K, ?> cache, final K key, int nThreads, final CountDownLatch gettersStartedSignal) throws InterruptedException {
final AtomicReferenceArray<Object> result = new AtomicReferenceArray<Object>(nThreads);
final CountDownLatch gettersComplete = new CountDownLatch(nThreads);
for (int i = 0; i < nThreads; i++) {
final int index = i;
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
gettersStartedSignal.countDown();
Object value = null;
try {
int mod = index % 3;
if (mod == 0) {
value = cache.get(key);
} else if (mod == 1) {
value = cache.getUnchecked(key);
} else {
cache.refresh(key);
value = cache.get(key);
}
result.set(index, value);
} catch (Throwable t) {
result.set(index, t);
}
gettersComplete.countDown();
}
});
thread.start();
// (in startSignal.await()), and the others waiting for that thread's result.
while (thread.isAlive() && thread.getState() != Thread.State.WAITING) {
Thread.yield();
}
}
gettersStartedSignal.countDown();
gettersComplete.await();
List<Object> resultList = Lists.newArrayListWithExpectedSize(nThreads);
for (int i = 0; i < nThreads; i++) {
resultList.add(result.get(i));
}
return resultList;
}
use of java.util.concurrent.atomic.AtomicReferenceArray in project hazelcast by hazelcast.
the class ThreadsafeCombinerTest method github_issue_3625.
/**
* Combiner creation is not threadsafe
*
* @throws Exception
*/
@Test
public void github_issue_3625() throws Exception {
class TestCombinerFactory implements CombinerFactory {
@Override
public Combiner newCombiner(Object key) {
return new Combiner() {
@Override
public void combine(Object value) {
}
@Override
public Object finalizeChunk() {
return null;
}
};
}
}
class CreationTask implements Runnable {
private final CountDownLatch latchStart;
private final CountDownLatch latchEnd;
private final AtomicReferenceArray<Combiner> array;
private final DefaultContext<Integer, Integer> defaultContext;
private final int index;
CreationTask(CountDownLatch latchStart, CountDownLatch latchEnd, AtomicReferenceArray<Combiner> array, DefaultContext<Integer, Integer> defaultContext, int index) {
this.latchStart = latchStart;
this.latchEnd = latchEnd;
this.array = array;
this.defaultContext = defaultContext;
this.index = index;
}
@Override
public void run() {
try {
latchStart.await();
Combiner combiner = defaultContext.getOrCreateCombiner(1);
array.set(index, combiner);
} catch (Exception e) {
e.printStackTrace();
} finally {
latchEnd.countDown();
}
}
}
int threadCount = 20;
AtomicReferenceArray<Combiner> combiners = new AtomicReferenceArray<Combiner>(threadCount);
DefaultContext<Integer, Integer> context = new DefaultContext<Integer, Integer>(new TestCombinerFactory(), null);
CountDownLatch latchStart = new CountDownLatch(1);
CountDownLatch latchEnd = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
Thread t = new Thread(new CreationTask(latchStart, latchEnd, combiners, context, i));
t.start();
}
latchStart.countDown();
latchEnd.await(1, TimeUnit.MINUTES);
for (int i = 0; i < threadCount - 1; i++) {
Combiner c1 = combiners.get(i);
Combiner c2 = combiners.get(i + 1);
assertTrue("Returned combiners are not identical: " + c1 + " -> " + c2, c1 == c2);
}
}
Aggregations