java - Possible to create AtomicReference that can be swapped atomically? -
is there way implement type of reference value can exchanged atomically?
in java have atomicreference
can swapped local variable not atomicreference
.
you can do:
atomicreference r1 = new atomicreference("hello"); atomicreference r2 = new atomicreference("world");
and swap them combination of 2 operations:
r1.set(r2.getandset(r1.get()));
but leaves them in inconsistent state in between, both contain "hello"
. if swap them atomically, still not read them (as pair) atomically.
what able is:
pairableatomicreference r1 = new pairableatomicreference("hello"); pairableatomicreference r2 = new pairableatomicreference("world"); atomicrefpair rp = new atomicrefpair(r1, r2);
then
object[] oldval, newval; { oldval = rp.get(); newval = new object[] {oldval[1], oldval[0]}; } while (! rp.compareandset(oldval, newval));
to swap values, , in thread:
atomicrefpair otherrp = new atomicrefpair(r1, r2); system.out.println(arrays.tostring(otherrp.get()));
and output either [hello, world]
or [world, hello]
.
notes:
r1
,r2
paired operation, it's possible thread independently pair,r1
,r3
(unfortunately means cannot use this solution.)- there hundreds of thousands of these references, global
reentrantlock
major bottleneck. rp
,otherrp
not shared between threads, locking them not work. interned, intern pool need own synchronization bottleneck.- i have made groups of 2 references here, ability group 3 or more bonus.
is possible implement lock-free version of atomicrefpair
? have hunch isn't, if not maybe there article somewhere explains why?
related: how atomically swap 2 ints in c#?
i don't know if there's nice solution, following ugly 1 work:
public final class myreference<t> extends reentrantlock implements comparable<myreference<t>> { public myreference() { id = counter.incrementandget(); } public void swap(myreference<t> other) { if (id < other.id) { lock(); other.lock(); } else { other.lock(); lock(); } final t tmp = value; value = other.value; other.value = tmp; unlock(); other.unlock(); } public static <t> list<t> consistentget(list<myreference<t>> references) { final arraylist<myreference<t>> sortedreferences = lists.newarraylist(references); collections.sort(sortedreferences); (val r : sortedreferences) r.lock(); final list<t> result = lists.newarraylistwithexpectedsize(sortedreferences.size()); (val r : references) result.add(r.value); (val r : sortedreferences) r.unlock(); return result; } @override public int compareto(myreference<t> o) { return id < o.id ? -1 : id > o.id ? 1 : 0; } private final static atomicinteger counter = new atomicinteger(); private t value; private final int id; }
- use myreference instead of atomicreference.
- it uses lot of locks, none of them global.
- it acquires locks in fixed order, it's deadlock-free.
- it compiles using lombok , guava (take pseudocode without them).
Comments
Post a Comment