📚 Pack de Estudio: Concurrencia

Procesos e Hilos en Java - Preparación del Examen

Test General de Concurrencia
15 preguntas tipo test sobre todo el temario. Selecciona la respuesta correcta en cada pregunta.
Tarjeta 1 de 20
Haz clic para ver la respuesta
Haz clic para volver

🖥️ Proceso vs. Hilo (Thread)

PROCESO

Instancia de un programa en ejecución.

  • Memoria Propia: Stack y Heap aislados.
  • Aislado: Un fallo no afecta a otros procesos.
  • Pesado: Lento para crear y comunicar.

Ejemplo: Abrir dos instancias de Notepad (dos procesos).

HILO (Thread)

Unidad de ejecución dentro de un proceso.

  • Memoria Compartida: Mismo Heap, Stack propio.
  • No Aislado: Un fallo afecta a todo el proceso.
  • Ligero: Rápido para crear y comunicar.

Ejemplo: Escribir texto (hilo UI) y guardar (hilo de fondo) en un solo Notepad.

🔄 Ciclo de Vida de un Hilo

1
NEW: `Thread t = new Thread();`
El objeto existe, pero el S.O. no sabe nada de él.
2
RUNNABLE: `t.start();`
El hilo está en la cola del planificador, listo para ejecutarse.
3
RUNNING: (Subestado de RUNNABLE)
El hilo está actualmente usando la CPU.

Estados de No Ejecución (Not Runnable)

BLOCKED

El hilo intenta entrar en un bloque `synchronized` pero otro hilo ya tiene el candado (monitor lock).

Vuelta a RUNNABLE: Cuando el candado es liberado.

WAITING

El hilo ha llamado a `objeto.wait()` o `hilo.join()` (sin tiempo).

Vuelta a RUNNABLE: Cuando es notificado (`notify()` / `notifyAll()`) o el hilo de `join()` muere.

TIMED_WAITING

El hilo ha llamado a `Thread.sleep(ms)`, `objeto.wait(ms)` o `hilo.join(ms)`.

Vuelta a RUNNABLE: Cuando el tiempo expira o es notificado.

4
TERMINATED: El método `run()` finaliza (normalmente o por excepción).
El hilo ha muerto y no puede volver a iniciarse.

🔒 Sincronización: Problema y Solución

PROBLEMA: Condición de Carrera

Varios hilos leen y escriben en un recurso compartido (ej: `saldo`) al mismo tiempo.

// saldo = 100
Hilo A lee (100)
Hilo B lee (100)
Hilo A escribe (101)
Hilo B escribe (101) // ¡Depósito perdido!

Resultado: Datos corruptos e impredecibles.

SOLUCIÓN: `synchronized`

Crea una "sección crítica" o "monitor lock". Solo un hilo puede entrar a la vez.

public synchronized void depositar() {
// Hilo A entra y bloquea
saldo = saldo + 1;
// Hilo B espera (BLOCKED)
} // Hilo A sale y libera

Resultado: Operación atómica y datos consistentes.

📄 Métodos Clave de `Thread`

Método Descripción Contexto
.start() Inicia el hilo. Llama a run() en un nuevo hilo de ejecución. ✅ OBLIGATORIO
.run() Contiene el código que ejecutará el hilo. (No llamar directamente). Implementar (Runnable) / Sobrescribir (Thread)
.join() El hilo actual espera (se bloquea) hasta que el hilo t termine. Coordinación
.sleep(ms) Pausa el hilo actual por 'ms' milisegundos. (Estado TIMED_WAITING). Simulación / Pausa
.interrupt() Envía una señal de interrupción al hilo. Detención / Señalización
.isAlive() Devuelve true si el hilo ha iniciado y no ha terminado. Verificación
Thread.currentThread() Método estático. Devuelve la instancia del hilo actual. Utilidad

🤝 Sincronización y Comunicación (Clase `Object`)

Método Descripción Contexto
synchronized (bloque/método) Adquiere el candado (monitor lock) del objeto. Previene Condiciones de Carrera. Atomicidad
.wait() Libera el candado y pone al hilo en estado WAITING (suspensión pasiva). Productor-Consumidor
.notify() Despierta a UN hilo aleatorio que esté en wait() sobre ese objeto. Productor-Consumidor
.notifyAll() Despierta a TODOS los hilos que estén en wait() sobre ese objeto. ✅ RECOMENDADO

⚖️ Comparativa de Estados de Espera

BLOCKED

Causa: Intentar entrar en un bloque `synchronized` que ya está ocupado.

Cómo sale: Automáticamente, cuando el otro hilo libera el candado.

Control: El programador no lo controla, es automático del monitor lock.

WAITING

Causa: Llamada explícita a `objeto.wait()` o `hilo.join()`.

Cómo sale: Llamada explícita a `objeto.notify()` o `notifyAll()` desde otro hilo.

Control: El programador lo controla para la comunicación entre hilos.

🖥️ Métodos Clave de `Process` y `ProcessBuilder`

Método Descripción
ProcessBuilder(cmd) Configura el comando a ejecutar (ej: "notepad.exe" o "cmd", "/c", "echo").
builder.inheritIO() Redirige la salida del proceso hijo a la consola del padre.
builder.start() Inicia el proceso externo y devuelve un objeto Process.
process.waitFor() Bloquea el hilo actual (Java) hasta que el proceso externo termine.
process.exitValue() Devuelve el código de salida del proceso (0 = éxito). Solo usar después de waitFor().
process.getInputStream() Obtiene el stream para LEER la SALIDA del proceso externo.

⚠️ IMPORTANTE - Errores Comunes

  • • Error: Llamar a `hilo.run()` en lugar de `hilo.start()`.
    Causa: Ejecuta el código en el hilo principal, no en uno nuevo.
  • • Error: Usar `if(lista.isEmpty()) wait();` en lugar de `while(...)`.
    Causa: Vulnerable a "Spurious Wakeups" (despertares falsos).
  • • Error: Llamar a `wait()` o `notify()` fuera de un bloque `synchronized`.
    Causa: Lanza `IllegalMonitorStateException`.
  • • Error: Usar `Thread.sleep()` para sincronizar (espera activa).
    Causa: Ineficiente y poco fiable. Usar `wait()`/`notify()`.
Instrucciones: Lee cada fragmento de código (basado en nuestros ejercicios) y responde a la pregunta.

💡 Consejos para código:

  • • `start()` crea un hilo, `run()` no.
  • • `synchronized` protege datos compartidos.
  • • `join()` espera a que un hilo muera.
  • • `wait()` libera el candado, `sleep()` no lo hace.
  • • `process.getInputStream()` es la SALIDA del proceso externo.
Instrucciones: Lee cada caso práctico y elige la mejor solución. Después de responder verás la explicación.