Interbloqueo de subprocesos de Java y su solución

Para comprender el interbloqueo de subprocesos, primero debemos comprender qué es un interbloqueo

 

Punto muerto

En términos sencillos: Deadlock es un fenómeno de bloqueo causado por la competencia por los recursos o por la comunicación entre dos o más procesos o subprocesos durante la ejecución, si no hay fuerza externa, no podrán avanzar.

 

Usemos un ejemplo más simple

 

Por ejemplo, en este ejemplo de atasco, se puede ver en la figura que los automóviles que viajan en cuatro direcciones se bloquean entre sí. Si no hay ningún automóvil que regrese en ninguna dirección, se formará un punto muerto.

Hay cuatro razones para el interbloqueo en la figura anterior:

1. Condiciones mutuamente excluyentes: un recurso solo puede ser utilizado por un hilo a la vez. Cada carretera en el mapa solo puede permitir el paso de automóviles en una dirección, por lo que se cumple una de las condiciones para el punto muerto.

2. Condiciones de solicitud y retención: cuando un proceso se bloquea al solicitar recursos, sigue reteniendo los recursos adquiridos. Se puede ver que los autos en cada dirección en el mapa están esperando que los autos en otras direcciones sean evacuados, por lo que se cumple la segunda condición para el punto muerto.

3. Condiciones de no privación: los recursos obtenidos por el proceso no pueden ser privados por la fuerza antes de que se agoten. Se asume aquí que no hay policía de tránsito, entonces nadie puede solicitar forzosamente la evacuación de autos en otras direcciones, por lo que se cumple la tercera condición de punto muerto.

4. Condición de espera cíclica: Se forma una especie de relación de recurso de espera cíclica entre varios procesos o subprocesos. Esto se expresa de manera muy intuitiva en la figura.
 

 

Ejemplo pequeño de código Java de interbloqueo

 

 

 

package huaxin2016_9_9;

public class ThreadDeadlock {
	public static void main(String[] args) throws InterruptedException {
		Object obj1 = new Object();
		Object obj2 = new Object();
		Object obj3 = new Object(); 
		//新建三个线程
		Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1"); 
		Thread t2 = new Thread(new SyncThread(obj2, obj3), "t2"); 
		Thread t3 = new Thread(new SyncThread(obj3, obj1), "t3"); 
		//让线程依次开始
		t1.start(); 
		//让线程休眠
		Thread.sleep(5000);
		t2.start();
		Thread.sleep(5000);
		t3.start();
	} 
} 
class SyncThread implements Runnable{ 
	private Object obj1; 
	private Object obj2;
	//构造函数
	public SyncThread(Object o1, Object o2){ 
		this.obj1=o1;
		this.obj2=o2;
	} 
	@Override
	public void run() {
		//获取并当前运行线程的名称
		String name = Thread.currentThread().getName();
		System.out.println(name + " acquiring lock on "+obj1);
		
		
		synchronized (obj1) { 
			System.out.println(name + " acquired lock on "+obj1); 
			work();
			System.out.println(name + " acquiring lock on "+obj2); 
			synchronized (obj2) { 
				System.out.println(name + " acquired lock on "+obj2); 
				work();
		    } 
			System.out.println(name + " released lock on "+obj2); 
	    } 
		System.out.println(name + " released lock on "+obj1); 
		System.out.println(name + " finished execution.");
	}
	private void work() { 
		try { 
			Thread.sleep(30000); 
		} 
		catch (InterruptedException e) { 
			e.printStackTrace();
		}
	} 
}

El resultado del pequeño ejemplo de interbloqueo anterior es

 

 

t1 acquiring lock on java.lang.Object@675d5ed4
t1 acquired lock on java.lang.Object@675d5ed4
t2 acquiring lock on java.lang.Object@7943f708
t2 acquired lock on java.lang.Object@7943f708
t3 acquiring lock on java.lang.Object@46767615
t3 acquired lock on java.lang.Object@46767615
t1 acquiring lock on java.lang.Object@7943f708
t2 acquiring lock on java.lang.Object@46767615
t3 acquiring lock on java.lang.Object@675d5ed4

Puede verse intuitivamente que t1, t2 y t3 están solicitando recursos, pero todos mantienen sus propios recursos, lo que provoca un punto muerto.

 

 

solución:

1. Para romper la condición mutuamente excluyente, necesitamos permitir que el proceso acceda a ciertos recursos al mismo tiempo, este método está sujeto al escenario real y no es fácil lograr la condición;

2. Romper la condición de no apropiación. De esta manera, debe permitir que el proceso se apodere de ciertos recursos por la fuerza del ocupante, o simplemente comprender que el proceso que ocupa el recurso ya no puede solicitar la ocupación de otros recursos. la aplicación debe ser liberada después de los recursos disponibles. Esto es en realidad también es difícil encontrar escenarios aplicables;

3. El proceso se aplica a todos los recursos antes de ejecutarse; de ​​lo contrario, el proceso no puede entrar en el estado listo para ejecutarse. Este método parece ser útil, pero su desventaja es que puede reducir la utilización de recursos y la concurrencia de procesos.

4. Evite los bucles de aplicación de recursos, es decir, clasifique y numere los recursos con anticipación y asígnelos según el número. Este método puede mejorar eficazmente la utilización de recursos y el rendimiento del sistema, pero aumenta la sobrecarga del sistema y aumenta el tiempo que el proceso consume recursos.

 

(1). El método más simple y más comúnmente utilizado es reiniciar el sistema, pero este método es muy costoso, significa que todo el trabajo de cálculo que ha sido completado por el proceso se desperdiciará, incluida la participación en la muerte. Procesos que son bloqueado, y procesos que no están involucrados en el punto muerto;

(2) Cancelar el proceso y privar de recursos. Terminar los procesos que participan en el interbloqueo y recuperar los recursos que ocupan, eliminando así el interbloqueo. En este momento, hay dos situaciones: cancelar todos los procesos que participan en el interbloqueo de una vez y privar de todos los recursos; o cancelar gradualmente los procesos que participan en el interbloqueo y recuperar gradualmente los recursos ocupados por el proceso de interbloqueo. En general, a la hora de elegir un proceso para ser cancelado gradualmente, se deben seguir ciertos principios. El propósito es cancelar el proceso con el menor costo, como determinar el costo del proceso de acuerdo con la prioridad del proceso; considerando el costo de el proceso cuando se está ejecutando y lo externo relacionado con el proceso Factores tales como el costo del trabajo;

(3). Estrategia de reversión del proceso, es decir, dejar que el proceso que participa en el punto muerto retroceda a un punto anterior al punto muerto, y Continúe la ejecución en este punto, para que no vuelva a suceder Deadlock. Aunque este es un método ideal, su operación es extremadamente costosa. Es necesario tener un mecanismo como una pila para registrar cada cambio en el proceso para futuras reversiones. A veces esto no es posible.

 

 

 

Supongo que te gusta

Origin blog.csdn.net/dream_18/article/details/52644903
Recomendado
Clasificación