18. StampedLock: ¿Hay un bloqueo más rápido que un bloqueo de lectura-escritura? -Herramientas de concurrencia

El rendimiento de StampedLock es mejor que el bloqueo de lectura-escritura

1. Tres modos de bloqueo compatibles con StampedLock

Tres modos: bloqueo de escritura, bloqueo de lectura pesimista y lectura optimista . Entre ellos, la semántica de los bloqueos de escritura y los bloqueos de lectura pesimista son muy similares a los de ReadWriteLock, que permite que múltiples hilos adquieran bloqueos de lectura pesimistas al mismo tiempo, pero solo permite que un hilo adquiera bloqueos de escritura. Los bloqueos de escritura y los bloqueos de lectura pesimista son mutuos. Reprendido La diferencia es que el bloqueo de escritura y el bloqueo de lectura pesimista en StampedLock devolverán un sello después de que el bloqueo se haya bloqueado correctamente; luego, al desbloquearlo, debe pasar este sello. El código de muestra relevante es el siguiente.

final StampedLock sl =  new StampedLock();
  
// 获取 / 释放悲观读锁示意代码
long stamp = sl.readLock();
try {
  // 省略业务相关代码
} finally {
  sl.unlockRead(stamp);
}
 
// 获取 / 释放写锁示意代码
long stamp = sl.writeLock();
try {
  // 省略业务相关代码
} finally {
  sl.unlockWrite(stamp);
}

ReadWriteLock admite múltiples hilos para leer al mismo tiempo, pero cuando se leen múltiples hilos al mismo tiempo, se bloquearán todas las operaciones de escritura; y las lecturas optimistas proporcionadas por StampedLock permiten que un hilo adquiera el bloqueo de escritura, lo que significa que no todas las operaciones de escritura Están bloqueados La operación de lectura optimista no tiene bloqueo .

class Point {
	private int x, y;
	final StampedLock sl = new StampedLock();

	// 计算到原点的距离
	int distanceFromOrigin() {
		// 乐观读
		long stamp = sl.tryOptimisticRead();
		// 读入局部变量,
		// 读的过程数据可能被修改
		int curX = x, curY = y;
		// 判断执行读操作期间,
		// 是否存在写操作,如果存在,
		// 则 sl.validate 返回 false
		if (!sl.validate(stamp)) {
			// 升级为悲观读锁
			stamp = sl.readLock();
			try {
				curX = x;
				curY = y;
			} finally {
				// 释放悲观读锁
				sl.unlockRead(stamp);
			}
		}
		return Math.sqrt(curX * curX + curY * curY);
	}
}

tryOptimisticRead () es una lectura optimista. Leer x e y también necesita verificar si se ha cambiado. Se verifica mediante validate (sello). Si se cambia, se actualiza a un bloqueo de lectura pesimista.

2. Comprender mejor la lectura optimista

Similar al bloqueo optimista de la base de datos. El bloqueo optimista de la base de datos se logra aumentando la versión del campo numérico.

3. Precauciones para usar StampedLock

  • La función de StampedLock es solo un subconjunto de ReadWriteLock;
  • StampedLock no admite la reentrada;
  • Los bloqueos de lectura y escritura pesimistas de StampedLock no admiten variables de condición
  • Si el hilo está bloqueado en el readLock () o writeLock () de StampedLock, llamar al método interrupt () del hilo bloqueado en este momento hará que la CPU se dispare. Por ejemplo, en el siguiente código, el hilo T1 se bloquea después de adquirir un bloqueo de escritura, y el hilo T2 intenta adquirir un bloqueo de lectura pesimista, y también bloquea; si llama al método interrupt () del hilo T2 para interrumpir el hilo T2, encontrará el hilo T2 Su CPU se elevará al 100%.
final StampedLock lock  = new StampedLock();
	Thread T1 = new Thread(()->{
	  // 获取写锁
	  lock.writeLock();
	  // 永远阻塞在此处,不释放写锁
	  LockSupport.park();
	});
	T1.start();
	// 保证 T1 获取写锁
	Thread.sleep(100);
	Thread T2 = new Thread(()->
	  // 阻塞在悲观读锁
	  lock.readLock()
	);
	T2.start();
	// 保证 T2 阻塞在读锁
	Thread.sleep(100);
	// 中断线程 T2
	// 会导致线程 T2 所在 CPU 飙升
	T2.interrupt();
	T2.join();

Cuando utilice StampedLock, no debe llamar a operaciones de interrupción. Si necesita admitir la función de interrupción, debe usar el bloqueo de lectura pesimista interrumpible readLockInterruptibly () y el bloqueo de escritura writeLockInterruptibly ().

Plantilla de lectura de StampedLock:

final StampedLock sl = 
  new StampedLock();
 
// 乐观读
long stamp = 
  sl.tryOptimisticRead();
// 读入方法局部变量
......
// 校验 stamp
if (!sl.validate(stamp)){
  // 升级为悲观读锁
  stamp = sl.readLock();
  try {
    // 读入方法局部变量
    .....
  } finally {
    // 释放悲观读锁
    sl.unlockRead(stamp);
  }
}
// 使用方法局部变量执行业务操作
......

Plantilla de escritura StampedLock:

long stamp = sl.writeLock();
try {
  // 写共享变量
  ......
} finally {
  sl.unlockWrite(stamp);
}
97 artículos originales publicados · elogiados 3 · 10,000+ vistas

Supongo que te gusta

Origin blog.csdn.net/qq_39530821/article/details/102646900
Recomendado
Clasificación