{
 "subtemas": [],
 "tarjetas": [
  {
   "sub": "Concurrencia",
   "q": "Ciclo de vida de un hilo en Java",
   "a": "NEW → (start) RUNNABLE → (corriendo / listo) → BLOCKED (esperando lock) → WAITING (wait/join sin timeout) → TIMED_WAITING (sleep/wait con timeout) → TERMINATED.\nNo se puede reiniciar un hilo terminado (IllegalThreadStateException): usa run() en lugar de start() NO crea hilo.",
   "nivel": "intermedio",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "Crear hilos: Runnable vs Thread vs Callable",
   "a": "Runnable: tarea sin resultado, new Thread(runnable).start().\nThread: heredar (acopla tarea con ejecución — evitar).\nCallable<V>: devuelve resultado y lanza excepciones checked — se usa con ExecutorService/Future.\nRecomendado: nunca crear hilos 'a mano'; usar pools (executors).",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "Race condition: qué es y el ejemplo de siempre",
   "a": "El resultado depende del entrelazado de hilos. Clásico: contador++ no es atómico (leer-modificar-escribir: 3 pasos) → dos hilos pueden leer el mismo valor y perder una suma.\nFixes: synchronized, AtomicInteger (CAS), LongAdder para contadores de alta contención.\nNo confundir con deadlock.",
   "nivel": "intermedio",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "synchronized: método vs bloque y sobre QUÉ se bloquea",
   "a": "Método de instancia: lock del objeto (this). Método static: lock del objeto Class (Clase.class).\nBloque: synchronized(otroObjeto) { } — lock específico, mínimo alcance recomendado.\nReentrante: el mismo hilo puede tomar el lock de nuevo.\nTodo lo compartido entre hilos debe protegerse con el MISMO lock.",
   "nivel": "intermedio",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "wait/notify/notifyAll: contrato exacto",
   "a": "Se llaman DENTRO de synchronized sobre el MISMO objeto monitor, sino IllegalMonitorStateException.\nwait(): libera el lock y espera; notify(): despierta UNO; notifyAll(): despierta todos (el más seguro — evita hilos dormidos para siempre).\nSiempre en un while(!condicion) wait() — para despertares espurios.\nHoy se prefiere java.util.concurrent (BlockingQueue, CountDownLatch).",
   "nivel": "avanzado",
   "clave": true
  },
  {
   "sub": "Concurrencia",
   "q": "Deadlock: las 4 condiciones y cómo prevenirlo",
   "a": "Exclusión mutua, retención y espera, no expulsión, espera circular.\nPrevención: adquirir locks en ORDEN GLOBAL consistente, usar tryLock con timeout (ReentrantLock), evitar locks anidados, granularidad fina.\nDetección: dump de hilos (jstack) muestra 'Found one Java-level deadlock'.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "ReentrantLock vs synchronized: cuándo el extra vale la pena",
   "a": "ReentrantLock: tryLock(timeout) (no bloquear indefinidamente), lockInterruptibly(), fairness (cola FIFO), múltiples Condition.\nCosto: debes hacer unlock() en finally SIEMPRE.\nRegla: synchronized por defecto; ReentrantLock solo para esas necesidades avanzadas.",
   "nivel": "intermedio",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "AtomicInteger y CAS: cómo funcionan sin locks",
   "a": "Compare-And-Swap: operación atómica de hardware — 'si el valor actual es X, ponme Y' — reintentando en loop si falló.\nAtomicInteger.incrementAndGet() es lock-free y muy rápido.\nLimitación: operaciones compuestas complejas (compareAndSet encadenado, acumulación con lógica → synchronized o LongAdder).\nOtros: AtomicReference, AtomicBoolean, AtomicLong.",
   "nivel": "intermedio",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "LongAdder vs AtomicLong",
   "a": "LongAdder: mantiene celdas múltiples que se suman al leer (sum()) — muchísimo mejor bajo ALTA CONTENCIÓN de escritura; lecturas ligeramente más caras.\nAtomicLong: todos los hilos CAS sobre un solo valor → colisiones.\nContadores de métricas → LongAdder.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "CountDownLatch vs CyclicBarrier vs Semaphore",
   "a": "CountDownLatch: cuenta regresiva de UNA VEZ (await espera a que count llegue a 0) — 'espera a que N tareas terminen'; no reutilizable.\nCyclicBarrier: N hilos se ESPERAN MUTUAMENTE en un punto; reutilizable; acción barrier opcional.\nSemaphore(N): permisos — limita acceso concurrente a un recurso (pool de conexiones); acquire/release.",
   "nivel": "intermedio",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "ExecutorService: ciclo de vida correcto",
   "a": "Crear: Executors.newFixedThreadPool(n), newCachedThreadPool (cuidado: hilos ilimitados), newSingleThreadExecutor, newScheduledThreadPool.\nEjecutar: submit (Callable → Future), execute (Runnable).\nCerrar: shutdown() (termina tareas pendientes, no acepta nuevas) → awaitTermination → shutdownNow() (interrumpe) en finally.\nNo cerrar = hilos no-daemon impiden salir de la JVM.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "¿Cómo dimensionar un pool de hilos?",
   "a": "CPU-bound: núcleos + 1 (Runtime.getRuntime().availableProcessors()).\nI/O-bound: más hilos porque pasan bloqueados: núcleos * (1 + tiempoEspera/tiempoCPU) o empíricamente decenas.\nEn servicios web: cada pool por dependencia (bulkhead) con colas ACOTADAS ( LinkedBlockingQueue sin límite = OOM).\nMedir y ajustar.",
   "nivel": "avanzado",
   "clave": true
  },
  {
   "sub": "Concurrencia",
   "q": "Future: qué ofrece y qué le falta",
   "a": "get() (bloquea, con timeout opcional), cancel(mayInterruptIfRunning), isDone/isCancelled.\nFalta: callbacks no bloqueantes, composición, manejo de errores elegante → por eso CompletableFuture.\nTrampa: get() sin timeout puede colgar para siempre.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "CompletableFuture: recetario de métodos",
   "a": "supplyAsync(tarea, executor) / runAsync.\nTransformar: thenApply (sync), thenApplyAsync.\nEncadenar: thenCompose (evita CF<CF<T>>), thenCombine (une dos independientes).\nConsumir: thenAccept/thenRun.\nErrores: exceptionally, handle, whenComplete.\nTodos los *Async aceptan executor propio (¡sino commonPool!).",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "ThreadLocal: qué es y su fuga de memoria clásica",
   "a": "Variable con valor POR HILO (cada hilo ve su copia): user context, transacciones, SimpleDateFormat legado.\nUso: ThreadLocal.withInitial(() -> new ...).\nFuga: en pools de hilos los hilos viven para siempre → si no haces remove() en el finally, el valor queda anclado para siempre.\nSiempre try { } finally { threadLocal.remove(); }.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "interrupt(): qué hace y qué no",
   "a": "NO detiene el hilo: pone un flag y hace que sleep/wait/join/bloqueos interrumpibles lancen InterruptedException.\nEl hilo decide cooperar: revisar Thread.currentThread().isInterrupted() en loops largos.\nLimpiar el flag al capturar la excepción si vas a continuar: Thread.currentThread().interrupt().",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "Hilos daemon vs usuario",
   "a": "Daemon: hilo de servicio (GC, monitores) — la JVM sale SIN esperarlos; setDaemon(true) ANTES de start().\nUsuario: la JVM espera a que terminen.\nTrampa: tareas críticas en daemon pueden cortarse a la mitad al cerrar la app.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "Colecciones thread-safe: mapa rápido de decisión",
   "a": "Map concurrente → ConcurrentHashMap (o ConcurrentSkipListMap si ordenado).\nLista concurrente → CopyOnWriteArrayList (muchas lecturas) o listas sincronizadas pequeñas.\nCola productor/consumidor → ArrayBlockingQueue (acotada) / LinkedBlockingQueue / ConcurrentLinkedQueue (lock-free).\nSet concurrente → ConcurrentHashMap.newKeySet().\nNUNCA Vector/Hashtable para código nuevo.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "¿Por qué 'double-checked locking' era difícil y cómo se arregla?",
   "a": "Singleton lazy: sin volatile, un hilo puede ver un objeto a medio construir (reordenamiento de instrucciones).\nFix: campo private static volatile Instancia instancia.\nAlternativas mejores: holder idiom (clase interna estática — lazy y thread-safe por classloading) o enum singleton.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "Happens-before: la idea central del Java Memory Model",
   "a": "Garantía de VISIBILIDAD: si la acción A happens-before B, todo lo que A escribió es visible para B.\nConstruyen happens-before: release/acquire del mismo lock (unlock→lock), escritura/lectura volatile, start()/join() de un hilo, métodos de concurrencia del paquete j.u.c.\nSin una de estas relaciones, los cambios pueden no verse NUNCA (reordenamiento + cachés de CPU).",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "¿Por qué volatile NO hace atómico i++?",
   "a": "volatile garantiza visibilidad y orden, no atomicidad compuesta: i++ sigue siendo leer+sumar+escribir (3 pasos que pueden entrelazarse).\nFix: AtomicInteger.incrementAndGet(), o synchronized.\nvolatile perfecto para: flags de estado (running = false), publicación de referencias inmutables.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "Singleton thread-safe: las 4 formas canónicas",
   "a": "1) Enum singleton (SimpleSingleton.INSTANCE) — la más segura.\n2) Holder idiom: clase interna estática con la instancia (lazy por classloading, sin locks).\n3) Double-checked locking con volatile.\n4) Campo static final inicializado al cargar (eager).\nEn Spring, el contenedor ya maneja singletons — casi no se escribe a mano.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "BlockingQueue: el patrón productor-consumidor en 3 líneas",
   "a": "ArrayBlockingQueue<Integer> cola = new ArrayBlockingQueue<>(100);\nProductor: cola.put(item) — bloquea si llena. Consumidor: cola.take() — bloquea si vacía.\nDesacopla velocidades, acota memoria (bounded), sin wait/notify manual.\nVariantes: LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue (entrega directa).",
   "nivel": "intermedio",
   "clave": true
  },
  {
   "sub": "Concurrencia",
   "q": "ForkJoinPool y work-stealing: para qué existe",
   "a": "Pool que DIVIDE tareas recursivamente (fork/join) y los hilos ROBAN trabajo de las colas de otros (work-stealing) → buen balanceo para divide & conquer (procesar árboles, parallel streams lo usan).\nRecursiveTask<V>/RecursiveAction; invoke()/compute().\nEs el commonPool por defecto de los parallel streams.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "Virtual threads (Java 21): qué cambian de verdad",
   "a": "Hilos ligeros gestionados por la JVM (no 1:1 con hilos del SO): millones posibles.\nPara I/O-bound: Thread.ofVirtual().start() o Executors.newVirtualThreadPerTaskExecutor(); el hilo se desmonta al bloquearse en I/O → concurrencia masiva con código SÍNCRONO simple (no callbacks).\nNO acelera CPU-bound. Evitar pooling de virtual threads (uno por tarea) y sincronización prolongada (pinning).",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "¿Qué es el 'pinning' de virtual threads?",
   "a": "Un virtual thread montado sobre un carrier no puede desmontarse si ejecuta synchronized prolongado o native (JNI) bloqueante → bloquea su hilo del SO (¡el recurso escaso que querías ahorrar!).\nJava 21+ y 24 han mitigado mucho el caso synchronized.\nWorkaround histórico: ReentrantLock en lugar de synchronized en hot paths de I/O.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "Immutabilidad como estrategia de concurrencia",
   "a": "Objetos inmutables NO necesitan locks: compartirlos es gratis y seguro (publicación segura vía volatile/final).\nDiseño: state en records inmutables, cambios = nueva instancia (copy-on-write mentalidad).\nEs la base de ConcurrentHashMap, CopyOnWrite*, akka/actores y del estilo funcional.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "ScheduledExecutorService: tareas periódicas correctas",
   "a": "scheduleAtFixedRate(tarea, ini, periodo): intenta ejecutar cada 'periodo' (fijo desde el inicio; si la tarea tarda más, se solapan las intenciones).\nscheduleWithFixedDelay(tarea, ini, delay): espera 'delay' ENTRE fin e inicio (nunca solapa).\nSi la tarea LANZA excepción, las siguientes se CANCELAN → try/catch interno obligatorio.",
   "nivel": "intermedio",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "¿Qué es la contención (contention) y cómo se reduce?",
   "a": "Tiempo que los hilos gastan esperando locks/recursos compartidos.\nReducir: scopes más cortos de synchronized, locks finos/por-striping (ConcurrentHashMap), estructuras lock-free (CAS), datos por hilo (ThreadLocal), inmutabilidad, LongAdder, particionar el estado.\nMedir: profilers de contención, JFR.",
   "nivel": "intermedio",
   "clave": false
  },
  {
   "sub": "Concurrencia",
   "q": "@Async en Spring vs CompletableFuture manual",
   "a": "@Async: Spring envuelve el método con un proxy y lo ejecuta en un executor configurado (TaskExecutor) — necesidad: @EnableAsync y NO self-invocation (mismo límite que @Transactional).\nCompletableFuture: control fino de composición y executor por llamada.\nAmbos devuelven Future/CompletableFuture si se quiere el resultado. Nunca anotar métodos private.",
   "nivel": "intermedio",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "¿Qué hace la JVM al ejecutar tu .class?",
   "a": "1) ClassLoader carga el bytecode (loading, linking —verify/prepare/resolve—, initializing).\n2) El intérprete ejecuta bytecode línea a línea.\n3) El compilador JIT (C1 cliente, C2 optimizador) detecta hotspots y compila a código máquina nativo con optimizaciones (inlining, escape analysis, loop unrolling).\n4) El GC gestiona el heap.\nResultado: arranque lento, luego muy rápido.",
   "nivel": "basico",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "Estructura de memoria de la JVM",
   "a": "Heap: objetos — Young (Eden + 2 Survivor) y Old/Tenured.\nMetaspace (Java 8+): metadatos de clases (reemplaza PermGen), en memoria nativa.\nStacks: uno por hilo (frames, variables locales).\nCode cache: JIT nativo.\nAdemás: direct buffers, thread stacks.\nFlags: -Xms/-Xmx (heap), -XX:MaxMetaspaceSize, -Xss (stack).",
   "nivel": "basico",
   "clave": true
  },
  {
   "sub": "JVM y rendimiento",
   "q": "G1 GC: cómo funciona en 5 puntos",
   "a": "GC por defecto desde Java 9.\n1) Divide el heap en regiones (~2048) iguales.\n2) Marca concurrente para saber vivos.\n3) Jóvenes: pausas cortas (copy entre regiones).\n4) Mixtas: recoge regiones viejas con más basura primero.\n5) Objetivo de pausa configurable: -XX:MaxGCPauseMillis=200.\nCompacta (sin fragmentación como CMS).",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "ZGC / Shenandoah vs G1: ¿cuándo low-latency?",
   "a": "ZGC/Shenandoah: pausas < 1-10 ms INDEPENDIENTES del tamaño del heap (TB de heap), casi todo concurrente.\nCosto: algo más de CPU total (concurrente) y footprint.\nPara: APIs con SLO de latencia estricta, heaps enormes.\nG1: balance por defecto excelente.\nActivar: -XX:+UseZGC.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "OutOfMemoryError: los tipos y qué significan",
   "a": "Java heap space: heap lleno de objetos vivos (fuga o -Xmx chico).\nGC overhead limit exceeded: >98% de tiempo en GC recuperando <2%.\nMetaspace: demasiadas clases (generación dinámica, fuga de classloaders).\nUnable to create native thread: límite de hilos del SO.\nDirect buffer memory: NIO buffers fuera del heap.\nDiagnóstico: heap dump (-XX:+HeapDumpOnOutOfMemoryError) + Eclipse MAT.",
   "nivel": "avanzado",
   "clave": true
  },
  {
   "sub": "JVM y rendimiento",
   "q": "Memory leak en Java (¡con GC!): las fuentes típicas",
   "a": "Colecciones estáticas que solo crecen (cachés sin eviction), ThreadLocal sin remove en pools, listeners/handlers no desregistrados, classloaders con despliegues calientes (tomcat), objetos anclados por campos estáticos, subcadenas/arrays grandes retenidos.\nSíntoma: heap sube escalonadamente y nunca baja; Full GCs frecuentes.\nHerramienta: heap dump + dominators tree (MAT).",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "Referencias fuertes, suaves, débiles y fantasmas",
   "a": "Strong: nunca se recolecta mientras sea alcanzable.\nSoftReference: se limpia ANTES de OOM — cachés de memoria sensibles.\nWeakReference: se limpia en el próximo GC si solo hay referencias débiles — WeakHashMap (metadatos asociados a objetos).\nPhantomReference: notificación post-mortem (cleanup de nativo; reemplazado por Cleaner).",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "Classloading: delegación padre-hijo",
   "a": "Jerarquía: Bootstrap → Platform → Application (→ custom).\nDelegación: el loader pide AL PADRE primero; si no lo encuentra, carga él — evita duplicar clases core y asegura que java.lang.String sea 'el' String.\nCarga perezosa: una clase se inicializa al PRIMER uso activo (new, acceso static).\nAplicaciones web contenedores usan loaders por app (aislamiento).",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "¿Qué mide un profiler y cuáles hay en el kit JVM?",
   "a": "CPU por método (hotspots), memoria/retención, hilos, I/O.\nHerramientas: JFR (Java Flight Recorder) + JMC — bajo overhead, producción; jconsole/visualvm (local); async-profiler (flame graphs).\nMetodología: medir ANTES de optimizar; regla 90/10 (pocos métodos concentran el tiempo).",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "Flame graphs: cómo leerlos en 30 segundos",
   "a": "Cada caja = un método en ejecución; ancho = proporción de tiempo muestrado.\nX axis: stack apilado (abajo = llamador); el ANCHO total es lo que importa.\nPlatachas anchas planas = hotspot claro.\nEn modo diff (antes/después) las mejoras se ven por colores.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "Autoboxing y rendimiento: el caso típico",
   "a": "En loops intensivos: List<Long> suma via boxed (cada operación crea objetos) vs long[] o IntStream.range().sum() (primitivos).\nlong total = 0; for (long x : array) total += x — gana por goleada.\nMedir con JMH si es crítico; microoptimizar sin datos es adivinar.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "¿Qué es JMH y por qué System.nanoTime() no basta para benchmarks?",
   "a": "JMH (OpenJDK Microbenchmark Harness): maneja warmup de JIT, dead-code elimination, aislamiento de forks, distribución estadística.\nnanoTime a mano mide el código optimizado-away o sin calentar (primeras ejecuciones lentas).\nUso: anotaciones @Benchmark, @State, fork, warmup — resultados en ops/time con percentiles.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "Escape analysis y optimizaciones del JIT",
   "a": "El JIT analiza si un objeto ESCAPA del método: si no, puede eliminar la asignación (scalar replacement), hacer inlining de métodos calientes y unrolling de loops.\nInlining es la reina: habilita todas las demás — métodos GRANDES o final/mega-mórficos (2 tipos reales máx) se inlinean mejor.\nConsecuencia: abstracciones 'gratis' si JIT las elimina; megamorfismo mata el inlining.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "Flags JVM que todo backend debería conocer",
   "a": "-Xms/-Xmx (heap inicial/máx, iguales en prod), -XX:MaxMetaspaceSize, -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath, -XX:MaxGCPauseMillis (G1), -Xlog:gc* (logs GC), -XX:+UseStringDeduplication (G1), -agentlib:jdwp (debug), -Dsystem.properties.\nProd: habilitar JFR: -XX:StartFlightRecording=duration=60s,filename=...",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "String deduplication y compact strings",
   "a": "Compact strings (Java 9+): byte[] Latin-1 cuando basta → ~50% menos memoria en textos occidentales.\nString deduplication (G1, -XX:+UseStringDeduplication): GC comparte arrays de chars idénticos entre Strings (para apps con millones de Strings duplicados).\nComplementarias a intern().",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "JVM y rendimiento",
   "q": "Cachés de CPU y localidad de datos: por qué ArrayList le gana a LinkedList",
   "a": "La CPU trae líneas de caché (64B) contiguas: recorrer un array es prefetch-friendly.\nLinkedList: cada nodo es un objeto suelto en el heap → cache misses en cada salto.\nRegla práctica: ArrayList casi siempre gana incluso en inserciones medias por la localidad.\nDatos contiguos = rendimiento (primitivos > objetos).",
   "nivel": "avanzado",
   "clave": false
  }
 ]
}