El establecimiento de un nuevo AtomicBoolean

OhNoOhYes:

Uso una AtomicBooleanpara hacer cumplir volatilela visibilidad entre los hilos. Un subproceso está actualizando el valor, otro hilo solamente lo está leyendo.

Digamos que el valor actual es true. Ahora dicen que un hilo de escritura establece su valor a truenuevo:

final AtomicBoolean b = new AtomicBoolean(); // shared between threads

b.set(true);
// ... some time later
b.set(true);

Después de esto 'ficticio' set(true), ¿hay una penalización en el rendimiento cuando el hilo de lectura llamadas get()? ¿El hilo de lectura tiene que volver a leer y almacenar en caché el valor?

Si ese es el caso, el hilo de escritura podría haber hecho:

b.compareAndSet(false, true);

De esta manera, el hilo de lectura solamente tiene que invalidar los cambios reales.

tevemadar:

compareAndSet():

public final boolean compareAndSet(boolean expect, boolean update) {
    int e = expect ? 1 : 0;
    int u = update ? 1 : 0;
    return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}

compareAndSwapInt() Ya es nativo:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
  UnsafeWrapper("Unsafe_CompareAndSwapInt");
  oop p = JNIHandles::resolve(obj);
  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
  return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END

Cuando Atomic::cmpxchgse genera algún lugar al comienzo de la ejecución de JVM como

  address generate_atomic_cmpxchg() {
    StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg");
    address start = __ pc();

    __ movl(rax, c_rarg2);
   if ( os::is_MP() ) __ lock();
    __ cmpxchgl(c_rarg0, Address(c_rarg1, 0));
    __ ret(0);

    return start;
  }

cmpxchgl() genera código x86 (que tiene una larga, camino de código heredado también, así que no copio que uno aquí):

 InstructionMark im(this);
 prefix(adr, reg);
 emit_byte(0x0F);
 emit_byte(0xB1);
 emit_operand(reg, adr);

0F B1es en realidad una CMPXCHGoperación. Si marca el código anterior, if ( os::is_MP() ) __ lock();emite un LOCKprefijo en máquinas multiprocesador (permítanme citar a saltar lock(), se emite un solo F0byte), por lo que prácticamente en todas partes.

Y como los CMPXCHGdocumentos dice:

Esta instrucción se puede utilizar con un prefijo LOCK para permitir que la instrucción a ser ejecutada atómicamente. Para simplificar la interfaz de bus del procesador, el operando de destino recibe un ciclo de escritura sin tener en cuenta el resultado de la comparación. El operando de destino se escribe de nuevo si la comparación falla; de lo contrario, el operando fuente está escrito en el destino. ( El procesador nunca se produce una bloqueado leer sin producir también una escritura bloqueado. )

Así que en una máquina con varios procesadores x86, el NOP-CAS también hace una escritura, que afectan a la línea de caché. (El énfasis fue añadido por mí)

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=188114&siteId=1
Recomendado
Clasificación