Este programa emplea Java multihilo para replicar el ciclo central de la película 'Triangle', utilizendo conceptos como hilos que escapan, contaminación de recursos compartidos y recursión infinita.
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Simulación del bucle temporal de 'Triangle' mediante hilos en Java.
* Metáforas:
* - El barco = espacio de memoria compartida.
* - Hilos Jessie = procesos demoníacos incontrolables.
* - Cuerpos/colgantes = fugas de memoria no recolectadas.
* - Lista de recuerdos = lecturas de datos sucios que causan déjà vu.
* - Bucle infinito = recursión sin condición de terminación.
*/
public class SimuladorBucleInfinito {
// Recursos compartidos (el barco)
static class Embarcacion {
// Contador de cuerpos (solo aumenta, nunca disminuye)
final AtomicInteger contadorCadaveres = new AtomicInteger(0);
// Contador de colgantes (incrementa con cada llegada)
final AtomicInteger contadorCollares = new AtomicInteger(0);
// Memoria compartida – datos residuales no seguros para hilos
final List<string> memorias = new CopyOnWriteArrayList<>();
// Hilos Jessie activos (para detección mutua)
final Set<Thread> jessiesActivos = ConcurrentHashMap.newKeySet();
// Imprime estado actual de recursos
void mostrarEstadisticas(String accion) {
System.out.printf("[Recursos] %s | Cuerpos: %d | Collares: %d | Memorias: %d | Jessie activos: %d%n",
accion, contadorCadaveres.get(), contadorCollares.get(),
memorias.size(), jessiesActivos.size());
}
}
// Hilo Jessie (proceso incontrolable)
static class Jessie implements Runnable {
private final int identificador;
private final Embarcacion barco;
private final Random aleatorio = new Random();
private boolean tieneRecuerdo = false;
// Límite global para evitar ejecución indefinida (demostración)
private static final int MAX_JESSIE = 8;
private static final AtomicInteger jessiesCreados = new AtomicInteger(0);
Jessie(int id, Embarcacion barco) {
this.identificador = id;
this.barco = barco;
jessiesCreados.incrementAndGet();
}
@Override
public void ejecutar() {
Thread hiloActual = Thread.currentThread();
String nombre = "Jessie-" + identificador;
hiloActual.setName(nombre);
// 1. Abordar el barco – inicio de fuga de hilo
barco.jessiesActivos.add(hiloActual);
barco.contadorCollares.incrementAndGet(); // Cada llegada añade un collante (fuga)
System.out.println(nombre + " abordó, collantes+1");
// 2. Detección de contaminación de memoria (déjà vu)
if (!barco.memorias.isEmpty()) {
tieneRecuerdo = true;
System.out.println(nombre + " siente familiaridad, hay " + barco.memorias.size() + " registros en memoria");
}
// Agregar recuerdo actual (dato sucio)
barco.memorias.add(nombre + " recuerdo: timestamp=" + System.currentTimeMillis());
System.out.println(nombre + " dejó un recuerdo");
// 3. Simular movimiento en el barco, posible encuentro con otros Jessie
try {
int tiempoEstadia = 5000 + aleatorio.nextInt(5000);
long inicio = System.currentTimeMillis();
while (System.currentTimeMillis() - inicio < tiempoEstadia) {
Thread.sleep(1000);
// Descubrir otros Jessie – consecuencia de múltiples hilos escapados
for (Thread otro : barco.jessiesActivos) {
if (otro != hiloActual && otro.isAlive()) {
System.out.println(nombre + " encontró a " + otro.getName() + ", conflicto inminente");
// Decisión aleatoria: eliminar al otro o ser eliminado
if (aleatorio.nextBoolean()) {
System.out.println(nombre + " eliminó a " + otro.getName());
barco.contadorCadaveres.incrementAndGet(); // Cuerpo añadido, fuga de memoria
barco.jessiesActivos.remove(otro);
otro.interrupt(); // Terminación forzada del hilo
System.out.println(nombre + " cuerpos+1, actual: " + barco.contadorCadaveres.get());
} else {
System.out.println(nombre + " fue eliminado por " + otro.getName());
barco.contadorCadaveres.incrementAndGet(); // Cuerpo propio añadido
barco.jessiesActivos.remove(hiloActual);
System.out.println(nombre + " muerte, cuerpos+1, actual: " + barco.contadorCadaveres.get());
return; // Hilo finaliza
}
}
}
// Evento aleatorio: encuentro con pasajeros
if (aleatorio.nextInt(100) < 30) {
System.out.println(nombre + " vio a otros pasajeros, sin incidentes");
}
}
} catch (InterruptedException e) {
System.out.println(nombre + " hilo interrumpido, muerte");
barco.jessiesActivos.remove(hiloActual);
return;
}
// 4. Supervivencia – pero defecto de código inicia nuevo ciclo (recursión)
barco.jessiesActivos.remove(hiloActual);
System.out.println(nombre + " completó el ciclo, regresa al muelle");
// Defecto: sin condición de parada, se crea un nuevo Jessie (salvo límite demo)
int creados = jessiesCreados.get();
if (creados < MAX_JESSIE) {
System.out.println(nombre + " no puede liberar su obsesión, vuelve a abordar -> creando Jessie-" + (creados + 1));
Jessie siguienteJessie = new Jessie(creados + 1, barco);
Thread siguienteHilo = new Thread(siguienteJessie::ejecutar);
siguienteHilo.start();
} else {
System.out.println("===== Límite de demostración alcanzado, no se crean más hilos =====");
barco.mostrarEstadisticas("Estado final");
}
}
}
// Programa principal (perspectiva de la muerte)
public static void main(String[] args) throws InterruptedException {
System.out.println("=== Inicio simulación: Bucle temporal en 'Triangle' ===");
Embarcacion barco = new Embarcacion();
// Primer Jessie – hilo original
Jessie primerJessie = new Jessie(1, barco);
Thread hilo1 = new Thread(primerJessie::ejecutar);
hilo1.start();
// Simular inyección periódica de nuevos Jessie (la muerte no puede controlar los hilos)
ScheduledExecutorService inyector = Executors.newScheduledThreadPool(1);
inyector.scheduleAtFixedRate(() -> {
int proximoId = Jessie.jessiesCreados.get() + 1;
if (proximoId <= Jessie.MAX_JESSIE) {
System.out.println("\n[Inyección] La muerte no logró detenerlo, nuevo Jessie-" + proximoId + " escapa al barco");
Jessie extraJessie = new Jessie(proximoId, barco);
Thread hiloExtra = new Thread(extraJessie::ejecutar);
hiloExtra.start();
} else {
inyector.shutdown();
}
}, 3, 2, TimeUnit.SECONDS);
// Forzar fin tras 30 segundos
Thread.sleep(30000);
System.out.println("\n=== Tiempo agotado, intentando recolectar hilos (llega la muerte) ===");
inyector.shutdownNow();
for (Thread t : barco.jessiesActivos) {
t.interrupt();
}
barco.mostrarEstadisticas("Terminación forzada");
System.out.println("=== Simulación finalizada ===");
System.exit(0);
}
}
</string>
Correspondencia entre escena de película y código
| Escena de 'Triangle' | Mapeo en el programa |
|---|---|
| Jess engaña a la muerte y no baja del barco | El hilo no termina normalmente, escapa a memoria compartida (el barco) |
| Cada vez que sube al barco, lleva un collante | contadorCollares.incrementAndGet() – objetos que solo aumentan, fuga de memoria |
| Cuerpos quedan en el barco tras asesinatos | contadorCadaveres.incrementAndGet() – igual fuga, el recolector de basura no los libera |
| Ciclos dejan recuerdos residuales | Lista memorias crece continuamente, causando déjà vu por lectura de datos sucios |
| Múltiples Jessies coexisten simultáneamenet | Conjunto jessiesActivos con varios hilos ejecutándose en paralelo |
| Jessies se cazan entre sí | Hilos iteran jessiesActivos, eliminan aleatoriamente a otros o son eliminados |
| Pensar que ha vuelto a casa, pero comienza nuevo ciclo | Método ejecutar() crea recursivamente un nuevo hilo Jessie al final |
| Programa sin condición de terminación real | Solo limitado por MAX_JESSIE para demostración; sin él, sería bucle infinito |
| La muerte no puede detener procesos escapados | Hilo principal intenta interrumpir, pero algunos hilos pueden quedar bloqueados |
Ejemplo de salida (fragmento)
=== Inicio simulación: Bucle temporal en 'Triangle' ===
Jessie-1 abordó, collantes+1
Jessie-1 dejó un recuerdo
[Recursos] Jessie-1 abordó | Cuerpos: 0 | Collares: 1 | Memorias: 1 | Jessie activos: 1
...
[Inyección] La muerte no logró detenerlo, nuevo Jessie-2 escapa al barco
Jessie-2 abordó, collantes+1
Jessie-2 siente familiaridad, hay 2 registros en memoria
Jessie-2 dejó un recuerdo
Jessie-1 encontró a Jessie-2, conflicto inminente
Jessie-1 eliminó a Jessie-2
Jessie-1 cuerpos+1, actual: 1
...
Jessie-3 abordó, collantes+1
...
===== Límite de demostración alcanzado, no se crean más hilos =====
[Recursos] Estado final | Cuerpos: 7 | Collares: 8 | Memorias: 12 | Jessie activos: 2
Para simular más fielmente la fuga de hilos, se puede aumentar MAX_JESSIE y ejecutar por tiempo prolongado, observando el crecimiento de cuerpos, collantes y memorias hasta un posible desbordamiento de memoria. Eliminando MAX_JESSIE, el programa entrará en recursión infinita, imitando un sistema colapsado. Agregar Thread.sleep(0) puede intensificar la competencia entre hilos, haciendo los conflictos más impredecibles.