La entrevista de la gran fábrica será: la relación entre AQS LockSupport Unsafe

Visión general

AQS es el marco básico para realizar varios bloqueos comerciales. Por ejemplo, la capa inferior de ReentrantLock es utilizar AQS. Podemos referirnos a ReentrantLock para implementar la lógica de bloqueo de nuestras propias necesidades específicas.

El marco AQS en sí mismo se basa en dos herramientas poderosas, Unsafe y LockSupport, que se puede decir que son la mano derecha.

Por lo tanto, comprender cómo se utilizan Unsafe y LockSupport en AQS nos ayuda a comprender los principios de implementación subyacentes de varios bloqueos y también puede responder sistemáticamente a preguntas relacionadas con AQS durante las entrevistas.

AQS 与 Inseguro

El uso de Inseguro en AQS es principalmente operación CAS.
P.ej:

/**
* CAS head field. Used only by enq.
* 入队时 CAS 修改队列 head
*/
private final boolean compareAndSetHead(Node update) {
    
    
	return unsafe.compareAndSwapObject(this, headOffset, null, update);
}

/**
* CAS tail field. Used only by enq.
* 入队时 CAS 修改队列 tail
*/
private final boolean compareAndSetTail(Node expect, Node update) {
    
    
	return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}

AQS 与 LockSupport

El uso de LockSupport en AQS se usa principalmente para el parque de subprocesos después de la puesta en cola y un subproceso en la cola de anulación de estacionamiento.

// 未获取到锁的线程被包装成 Node,然后加入队列中
// 进入队列的 Node 如果处在 head,则尝试抢锁一次
// 若不在 head 位置或在 head 抢锁不成功,则进入 park
final boolean acquireQueued(final Node node, int arg) {
    
    
	boolean failed = true;
	try {
    
    
		boolean interrupted = false;
		for (;;) {
    
    
			final Node p = node.predecessor(); // 返回前一个节点
			if (p == head && tryAcquire(arg)) {
    
     // 前一个节点是head,则尝试抢锁一次
				setHead(node); // 抢锁成功,自己变为 head
				p.next = null; // help GC
				failed = false;
				return interrupted;
			}
			if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) // 若 Lock 的逻辑是抢锁失败后 park,则这里让线程进入 park
				interrupted = true;
		}
	} finally {
    
    
		if (failed)
			cancelAcquire(node);
	}
}

// 入队的线程 park
private final boolean parkAndCheckInterrupt() {
    
    
	LockSupport.park(this);
	return Thread.interrupted();
}

LockSupport 与 Inseguro

Los dos métodos principales de LockSupport, park () y unpark (Thread thread), se implementan internamente a través de métodos Unsafe.

// LockSupport 的 park 方法直接调用 Unsafe#park
public static void park() {
    
    
	UNSAFE.park(false, 0L);
}
// LockSupport 的 unpark 方法直接调用 Unsafe#unpark
public static void unpark(Thread thread) {
    
    
	if (thread != null)
		UNSAFE.unpark(thread);
}

Principio de desaparición de parque inseguro

En el sistema Linux, se implementa utilizando el mutex (exclusión mutua) y la condición (variable de condición) en la biblioteca de subprocesos Posix pthread. Y en el proceso de park unpark, se protege una variable _counter.

Al llamar a park, primero intente obtener el "permiso" directamente, es decir, si se juzga _counter> 0, si tiene éxito, configure _counter en 0 y regrese. De lo contrario, ingrese a la espera.

Al llamar a unpark, establezca directamente _counter en 1 y luego desbloquee el mutex para regresar. Si el valor anterior de _counter es 0, se debe llamar a pthread_cond_signal para despertar los hilos que esperan en el parque.

La explicación del código fuente puede referirse al análisis del código fuente de LockSupport (aparcar / desempacar)

La diferencia entre LockSupport y esperar notificación

  1. esperar notificar debe ser llamado después de sincronizado adquiere el bloqueo
  2. notificar notificar Todo no puede despertar un hilo con precisión, unpark (hilo) puede hacerlo
  3. LockSupport # unpark (Thread) se puede ejecutar antes que Thread park (), en este caso, Thread park () regresará inmediatamente (porque el _counter subyacente> 0)

【referencia】

  1. https://www.jianshu.com/p/e3afe8ab8364

Supongo que te gusta

Origin blog.csdn.net/hugo_lei/article/details/105813614
Recomendado
Clasificación