¿Hay alguna manera de implementar un tipo de referencia cuyo valor se pueda intercambiar con otro atómicamente?Posible crear AtomicReference que se puede intercambiar atómicamente?
En Java tenemos AtomicReference
que puede ser intercambiado con una variable local, pero no con otro AtomicReference
.
Usted puede hacer:
AtomicReference r1 = new AtomicReference("hello");
AtomicReference r2 = new AtomicReference("world");
e intercambiarlos con una combinación de dos operaciones:
r1.set(r2.getAndSet(r1.get()));
Pero esto les deja en un estado inconsistente en el medio, donde ambos contienen "hello"
. Además, incluso si pudieras intercambiarlos atómicamente, aún no podrías leerlos (como un par) atómicamente.
Lo que me gustaría ser capaz de hacer es:
PairableAtomicReference r1 = new PairableAtomicReference("hello");
PairableAtomicReference r2 = new PairableAtomicReference("world");
AtomicRefPair rp = new AtomicRefPair(r1, r2);
continuación
Object[] oldVal, newVal;
do {
oldVal = rp.get();
newVal = new Object[] {oldVal[1], oldVal[0]};
} while (! rp.compareAndSet(oldVal, newVal));
para cambiar los valores, y en otro hilo:
AtomicRefPair otherRP = new AtomicRefPair(r1, r2);
System.out.println(Arrays.toString(otherRP.get()));
y asegúrese de que la salida sea [hello, world]
o [world, hello]
.
Notas:
r1
yr2
están emparejados para esta operación, pero es posible que otro hilo se asociará de forma independiente, dicenr1
y otror3
- Hay (por desgracia eso significa que no puedo usar this solution). serán cientos de miles de estas referencias, por lo que un
ReentrantLock
global sería un cuello de botella importante. rp
yotherRP
no son necesariamente compartidos entre subprocesos, por lo tanto, simplemente bloquearlos no funcionará. Podrían ser interned, pero el grupo interno necesitaría su propia sincronización, que sería otro cuello de botella.- Solo he hecho grupos de 2 referencias aquí, pero la posibilidad de agrupar 3 o más sería una ventaja.
¿Es posible implementar una versión sin cerradura de AtomicRefPair
? Tengo la corazonada de que no es así, pero si no, tal vez haya un artículo en alguna parte que explique por qué.
relacionados: How do I atomically swap 2 ints in C#?
Hay un Interner en Guava, que usa ConcurrentHashMap, por lo que la contención podría ser arbitrariamente pequeña en promedio. – maaartinus