La condición deslizada es un tipo especial de condición de carrera que puede ocurrir en una aplicación multiproceso. En este, un hilo se suspende después de leer una condición y antes de realizar las actividades relacionadas con ella. Raramente ocurre, sin embargo, uno debe buscarlo si el resultado no es el esperado.
Ejemplo : supongamos que hay dos subprocesos A y B que desean procesar una string S. En primer lugar, se inicia el subproceso A , comprueba si quedan más caracteres para procesar, inicialmente toda la string está disponible para su procesamiento, por lo que la condición es verdadera. Ahora, el subproceso A está suspendido y el subproceso B comienza. Vuelve a verificar la condición, que se evalúa como verdadera y luego procesa toda la string S. Ahora, cuando el subproceso A comienza nuevamente la ejecución, la string S se procesa por completo en este momento y, por lo tanto, se produce un error. Esto se conoce como una condición deslizada.
Programa para demostrar condiciones deslizadas en Java
// Java program to demonstrate // slipped conditions public class Main { public static void main(String[] args) { ReadingThread readingThread = new ReadingThread(); SlippedThread slippedThread = new SlippedThread(); slippedThread.start(); readingThread.start(); } } class CommonResource { static final String string = "Hello"; static int pointerPosition = 0; } // Thread to demonstrate a slipped condition class SlippedThread extends Thread { @Override public void run() { // Check if any characters // are left to process if (CommonResource.pointerPosition != CommonResource.string.length()) { System.out.println("Characters left! " + "I can process the string"); // Cause the thread to wait to cause // a slipped condition try { synchronized (this) { wait(500); } } catch (InterruptedException e) { System.out.println(e); } try { while (CommonResource.pointerPosition < CommonResource.string.length()) { System.out.println("Thread1 " + CommonResource.string .charAt( CommonResource .pointerPosition)); CommonResource.pointerPosition++; } } catch (StringIndexOutOfBoundsException e) { System.out.println("\nNo more character left" + " to process. This is a" + " slipped condition"); } } } } // Thread to process the whole String class ReadingThread extends Thread { @Override public void run() { System.out.println("Thread2 trying to " + "process the string"); while (CommonResource.pointerPosition < CommonResource.string.length()) { System.out.print("Thread2 " + CommonResource.string .charAt( CommonResource .pointerPosition)); CommonResource.pointerPosition++; } } }
Characters left! I can process the string Thread2 trying to process the string Thread2 H Thread2 e Thread2 l Thread2 l Thread2 o No more character left to process. This is a slipped condition
La solución al problema de las condiciones deslizadas es bastante simple y directa . Cualquier recurso al que vaya a acceder un subproceso después de verificar la condición, debe estar bloqueado por el subproceso y solo debe liberarse después de que el subproceso haya realizado el trabajo. Todos los accesos deben estar sincronizados .
Con respecto al problema anterior, las condiciones deslizadas se pueden eliminar bloqueando el objeto String de la clase CommonResource . En este escenario, el subproceso primero obtiene acceso y bloquea la string y luego intenta procesar la string.
Solución al ejemplo anterior
public class Main { public static void main(String[] args) { ReadingThread readingThread = new ReadingThread(); SlippedThread slippedThread = new SlippedThread(); slippedThread.start(); readingThread.start(); } } class CommonResource { static final String string = "Hello"; static int pointerPosition = 0; // A static variable added // to lock the String object static boolean isLocked = false; } // Thread to demonstrate a slipped condition class SlippedThread extends Thread { @Override public void run() { // Check if any characters // are left to process if (CommonResource.isLocked != true && CommonResource.pointerPosition != CommonResource.string.length()) { System.out.println("Characters left! " + "I can process the string"); CommonResource.isLocked = true; // Cause the thread to wait to cause // a slipped condition try { synchronized (this) { wait(250); } } catch (InterruptedException e) { System.out.println(e); } try { while (CommonResource.pointerPosition < CommonResource.string.length()) { System.out.println("Thread1 " + CommonResource .string.charAt( CommonResource .pointerPosition)); CommonResource.pointerPosition++; } } catch (StringIndexOutOfBoundsException e) { System.out.println("\nNo more character " + "left to process. This is " + "a slipped condition"); } CommonResource.isLocked = false; } } } // Thread to process the whole String class ReadingThread extends Thread { @Override public void run() { System.out.println("Thread2 trying to" + " process the string"); if (CommonResource.isLocked == false) { CommonResource.isLocked = true; synchronized (this) { while (CommonResource.pointerPosition < CommonResource.string.length()) { System.out.println("Thread2 " + CommonResource.string .charAt( CommonResource .pointerPosition)); CommonResource.pointerPosition++; } } } CommonResource.isLocked = false; } }
Producción
Characters left! I can process the string Thread2 trying to process the string Thread1 H Thread1 e Thread1 l Thread1 l Thread1 o
En el programa anterior, se agrega un nuevo miembro booleano estático isLocked a la clase CommonResource . Ahora, cada vez que un subproceso intenta procesar la string, primero obtiene el bloqueo y luego lo procesa. En este ejemplo, el subproceso SlippedCondition comprueba si isLocked es falso y si queda una string por procesar. Si es así, obtiene el bloqueo y luego espera y finalmente procesa la string. Mientras tanto, ReadingThread intenta procesar la string, pero no puede, ya que SlippedThread estableció isLocked como verdadero .
Publicación traducida automáticamente
Artículo escrito por CharchitKapoor y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA