Synchronized Problems

Synchronized problems

En Java, cuando se usa synchronized en métodos, el bloqueo (lock) depende de si el método es de instancia o estático.

1. Si los métodos son de instancia (synchronized en métodos no estáticos):

Cuando declaras métodos como synchronized en una instancia de la clase, el bloqueo se aplica al objeto en el que se ejecuta el método. Es decir, cada instancia de la clase tiene su propio lock.

class Recurso {
    public synchronized void metodo1() {
        System.out.println("Método 1 en ejecución...");
        try { Thread.sleep(3000); } catch (InterruptedException e) {}
        System.out.println("Método 1 terminado.");
    }

    public synchronized void metodo2() {
        System.out.println("Método 2 en ejecución...");
        try { Thread.sleep(3000); } catch (InterruptedException e) {}
        System.out.println("Método 2 terminado.");
    }
}

public class Main {
    public static void main(String[] args) {
        Recurso recurso = new Recurso();

        Thread t1 = new Thread(() -> recurso.metodo1());
        Thread t2 = new Thread(() -> recurso.metodo2());

        t1.start();
        t2.start();
    }
}

🔹 Aquí, t1 y t2 comparten el mismo objeto recurso.

🔹 Cuando t1 entra a metodo1(), obtiene el bloqueo sobre la instancia recurso, por lo que t2 no podrá entrar a metodo2() hasta que metodo1() termine.

🔹 Esto significa que los dos métodos se ejecutarán en serie, no en paralelo.


2. Si los métodos son static synchronized (métodos estáticos sincronizados)

Si los métodos son estáticos y tienen synchronized, el bloqueo se aplica a la clase (Class), no a una instancia específica.

Ejemplo:

class Recurso {
    public static synchronized void metodo1() {
        System.out.println("Método 1 en ejecución...");
        try { Thread.sleep(3000); } catch (InterruptedException e) {}
        System.out.println("Método 1 terminado.");
    }

    public static synchronized void metodo2() {
        System.out.println("Método 2 en ejecución...");
        try { Thread.sleep(3000); } catch (InterruptedException e) {}
        System.out.println("Método 2 terminado.");
    }
}

public class Main {
    public static void main(String[] args) {
        Thread t1 = new Thread(Recurso::metodo1);
        Thread t2 = new Thread(Recurso::metodo2);

        t1.start();
        t2.start();
    }
}

🔹 Aquí, t1 y t2 bloquean a la clase Recurso.class, no a instancias específicas.

🔹 Como ambos métodos son static synchronized, cuando un hilo entra en metodo1(), otro hilo no puede entrar a metodo2() hasta que se libere el bloqueo de la clase.

🔹 De nuevo, los métodos se ejecutarán en serie.


3. Si los métodos pertenecen a diferentes instancias

Si tienes dos instancias diferentes de la clase, cada instancia tiene su propio lock, y los métodos pueden ejecutarse en paralelo:

class Recurso {
    public synchronized void metodo() {
        System.out.println(Thread.currentThread().getName() + " en ejecución...");
        try { Thread.sleep(3000); } catch (InterruptedException e) {}
        System.out.println(Thread.currentThread().getName() + " terminado.");
    }
}

public class Main {
    public static void main(String[] args) {
        Recurso recurso1 = new Recurso();
        Recurso recurso2 = new Recurso();

        Thread t1 = new Thread(() -> recurso1.metodo(), "Thread-1");
        Thread t2 = new Thread(() -> recurso2.metodo(), "Thread-2");

        t1.start();
        t2.start();
    }
}

🔹 Aquí t1 y t2 operan sobre recurso1 y recurso2 respectivamente.

🔹 Como los locks son a nivel de instancia, no se bloquean mutuamente.

🔹 Los métodos se ejecutarán en paralelo.


Conclusión

  • Si los métodos synchronized son de instancia, comparten el mismo lock solo si están en la misma instancia.
  • Si los métodos synchronized son estáticos, comparten el lock de la clase, bloqueando cualquier otro método static synchronized.
  • Si los métodos están en diferentes instancias, no comparten el lock y pueden ejecutarse en paralelo.