Concurrencia y multihilo en Java: guía completa

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Concurrencia y subprocesamiento múltiple en Java: desde lo básico hasta técnicas avanzadas



Las aplicaciones modernas requieren el máximo rendimiento. En Java, la concurrencia y el subprocesamiento múltiple son herramientas clave para el uso eficiente de procesadores multinúcleo. En este artículo, analizaremos cómo trabajar correctamente con subprocesos, sincronización y utilidades modernas de concurrencia.



¿Qué es el subprocesamiento múltiple en Java?

El subprocesamiento múltiple es la capacidad de un programa para ejecutar varias tareas simultáneamente. En Java, cada subproceso (thread) es un proceso ligero que tiene su propia pila de llamadas. Las principales ventajas son:

  • Aumento del rendimiento mediante la ejecución paralela
  • Interfaz de usuario más receptiva
  • Uso eficiente de los recursos de la CPU


Creación de subprocesos: dos enfoques

En Java hay dos formas principales de crear un subproceso:



1. Herencia de la clase Thread

public class MyThread extends Thread {    @Override    public void run() {        System.out.println("El subproceso se está ejecutando: " + Thread.currentThread().getName());    }

public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // Inicio del subproceso }}


2. Implementación de la interfaz Runnable

public class Task implements Runnable {    @Override    public void run() {        System.out.println("La tarea se ejecuta en el subproceso: " + Thread.currentThread().getName());    }

public static void main(String[] args) { Thread thread = new Thread(new Task()); thread.start(); }}

Se recomienda usar Runnable, ya que no limita la posibilidad de heredar de otras clases.



Sincronización de subprocesos: evitando condiciones de carrera

Cuando varios subprocesos acceden a datos compartidos, surgen problemas de sincronización. Veamos un ejemplo clásico: un contador:



public class Counter {    private int count = 0;

public synchronized void increment() { count++; }

public synchronized int getCount() { return count; }}

La palabra clave synchronized garantiza que solo un subproceso pueda ejecutar el método a la vez. Una alternativa es usar Lock del paquete java.util.concurrent.locks.



Deadlock: cómo evitar el bloqueo mutuo

Un deadlock ocurre cuando dos subprocesos esperan la liberación de recursos del otro. Ejemplo:

public class DeadlockExample {    private final Object lock1 = new Object();    private final Object lock2 = new Object();

public void method1() { synchronized (lock1) { synchronized (lock2) { // Sección crítica } } }

public void method2() { synchronized (lock2) { synchronized (lock1) { // Sección crítica } } }}

Para evitar deadlocks, siempre adquiera los bloqueos en el mismo orden o use tryLock() con tiempo de espera.



ExecutorService: gestión del grupo de subprocesos

Crear subprocesos manualmente no es eficiente. Java proporciona ExecutorService para gestionar un grupo de subprocesos:



import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;

public class ThreadPoolExample { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(4);

for (int i = 0; i < 10; i++) { executor.submit(() -> { System.out.println("Ejecutándose en: " + Thread.currentThread().getName()); }); }

executor.shutdown(); // Finalización después de ejecutar todas las tareas }}

Principales

Blogs

Book Recommendations