use of java.util.concurrent.atomic.AtomicReferenceArray in project gocd by gocd.
the class ConcurrentHashMapV8 method internalComputeIfAbsent.
/** Implementation for computeIfAbsent */
private final Object internalComputeIfAbsent(K k, Fun<? super K, ?> mf) {
int h = spread(k.hashCode());
Object val = null;
int count = 0;
for (AtomicReferenceArray<Node> tab = table; ; ) {
Node f;
int i, fh;
Object fk, fv;
if (tab == null)
tab = initTable();
else if ((f = tabAt(tab, i = (tab.length() - 1) & h)) == null) {
Node node = new Node(fh = h | LOCKED, k, null, null);
if (casTabAt(tab, i, null, node)) {
count = 1;
try {
if ((val = mf.apply(k)) != null)
node.val = val;
} finally {
if (val == null)
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;
boolean added = false;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
count = 1;
TreeNode p = t.getTreeNode(h, k, t.root);
if (p != null)
val = p.val;
else if ((val = mf.apply(k)) != null) {
added = true;
count = 2;
t.putTreeNode(h, k, val);
}
}
} finally {
t.release(0);
}
if (count != 0) {
if (!added)
return val;
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) {
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)) {
boolean added = false;
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))) {
val = ev;
break;
}
Node last = e;
if ((e = e.next) == null) {
if ((val = mf.apply(k)) != null) {
added = true;
last.next = new Node(h, k, val, 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 (!added)
return val;
if (tab.length() <= 64)
count = 2;
break;
}
}
}
}
if (val != null) {
counter.add(1L);
if (count > 1)
checkForResize();
}
return val;
}
use of java.util.concurrent.atomic.AtomicReferenceArray in project guava by google.
the class CacheLoadingTest method ignoreTestExpandDuringRefresh.
// Test ignored because it is extremely flaky in CI builds
public void ignoreTestExpandDuringRefresh() throws InterruptedException, ExecutionException {
final AtomicInteger callCount = new AtomicInteger();
// tells the computing thread when to start computing
final CountDownLatch computeSignal = new CountDownLatch(1);
// tells the main thread when computation is pending
final CountDownLatch secondSignal = new CountDownLatch(1);
// tells the main thread when the second get has started
final CountDownLatch thirdSignal = new CountDownLatch(1);
// tells the main thread when the third get has started
final CountDownLatch fourthSignal = new CountDownLatch(1);
// tells the test when all gets have returned
final CountDownLatch doneSignal = new CountDownLatch(3);
final String suffix = "Suffix";
CacheLoader<String, String> computeFunction = new CacheLoader<String, String>() {
@Override
public String load(String key) throws InterruptedException {
callCount.incrementAndGet();
secondSignal.countDown();
computeSignal.await();
return key + suffix;
}
};
final AtomicReferenceArray<String> result = new AtomicReferenceArray<String>(2);
final LoadingCache<String, String> cache = CacheBuilder.newBuilder().build(computeFunction);
final String key = "bar";
cache.asMap().put(key, key);
// start computing thread
new Thread() {
@Override
public void run() {
cache.refresh(key);
doneSignal.countDown();
}
}.start();
// wait for computation to start
secondSignal.await();
checkNothingLogged();
// start waiting thread
new Thread() {
@Override
public void run() {
thirdSignal.countDown();
result.set(0, cache.getUnchecked(key));
doneSignal.countDown();
}
}.start();
// give the second get a chance to run; it is okay for this to be racy
// as the end result should be the same either way
thirdSignal.await();
Thread.yield();
// Expand!
CacheTesting.forceExpandSegment(cache, key);
// start another waiting thread
new Thread() {
@Override
public void run() {
fourthSignal.countDown();
result.set(1, cache.getUnchecked(key));
doneSignal.countDown();
}
}.start();
// give the third get a chance to run; it is okay for this to be racy
// as the end result should be the same either way
fourthSignal.await();
Thread.yield();
// let computation finish
computeSignal.countDown();
doneSignal.await();
assertTrue(callCount.get() == 1);
assertEquals(key, result.get(0));
assertEquals(key, result.get(1));
assertEquals(key + suffix, cache.getUnchecked(key));
}
use of java.util.concurrent.atomic.AtomicReferenceArray in project guava by google.
the class CacheLoadingTest method testExpandDuringLoading.
public void testExpandDuringLoading() throws InterruptedException {
final int count = 3;
final AtomicInteger callCount = new AtomicInteger();
// tells the computing thread when to start computing
final CountDownLatch computeSignal = new CountDownLatch(1);
// tells the main thread when computation is pending
final CountDownLatch secondSignal = new CountDownLatch(1);
// tells the main thread when the second get has started
final CountDownLatch thirdSignal = new CountDownLatch(1);
// tells the main thread when the third get has started
final CountDownLatch fourthSignal = new CountDownLatch(1);
// tells the test when all gets have returned
final CountDownLatch doneSignal = new CountDownLatch(count);
CacheLoader<String, String> computeFunction = new CacheLoader<String, String>() {
@Override
public String load(String key) throws InterruptedException {
callCount.incrementAndGet();
secondSignal.countDown();
computeSignal.await();
return key + "foo";
}
};
final LoadingCache<String, String> cache = CacheBuilder.newBuilder().weakKeys().build(computeFunction);
final AtomicReferenceArray<String> result = new AtomicReferenceArray<String>(count);
final String key = "bar";
// start computing thread
new Thread() {
@Override
public void run() {
result.set(0, cache.getUnchecked(key));
doneSignal.countDown();
}
}.start();
// wait for computation to start
secondSignal.await();
// start waiting thread
new Thread() {
@Override
public void run() {
thirdSignal.countDown();
result.set(1, cache.getUnchecked(key));
doneSignal.countDown();
}
}.start();
// give the second get a chance to run; it is okay for this to be racy
// as the end result should be the same either way
thirdSignal.await();
Thread.yield();
// Expand!
CacheTesting.forceExpandSegment(cache, key);
// start another waiting thread
new Thread() {
@Override
public void run() {
fourthSignal.countDown();
result.set(2, cache.getUnchecked(key));
doneSignal.countDown();
}
}.start();
// give the third get a chance to run; it is okay for this to be racy
// as the end result should be the same either way
fourthSignal.await();
Thread.yield();
// let computation finish
computeSignal.countDown();
doneSignal.await();
assertTrue(callCount.get() == 1);
assertEquals("barfoo", result.get(0));
assertEquals("barfoo", result.get(1));
assertEquals("barfoo", result.get(2));
assertEquals("barfoo", cache.getUnchecked(key));
}
use of java.util.concurrent.atomic.AtomicReferenceArray in project guava by hceylan.
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 aerospike-client-java by aerospike.
the class Command method getSequenceNode.
private final Node getSequenceNode(Cluster cluster, Partition partition) {
// Must copy hashmap reference for copy on write semantics to work.
HashMap<String, AtomicReferenceArray<Node>[]> map = cluster.partitionMap;
AtomicReferenceArray<Node>[] replicaArray = map.get(partition.namespace);
if (replicaArray != null) {
for (int i = 0; i < replicaArray.length; i++) {
int index = Math.abs(sequence % replicaArray.length);
Node node = replicaArray[index].get(partition.partitionId);
if (node != null && node.isActive()) {
return node;
}
sequence++;
}
}
return cluster.getRandomNode();
}
Aggregations