Saltar al contenido principal

sincronizado Palabra clave en Java

La palabra clave synchronized en Java controla el acceso a los recursos compartidos entre varios subprocesos. Garantiza que sólo un hilo pueda ejecutar un bloque o método sincronizado a la vez, evitando interferencias entre hilos y asegurando la coherencia de la memoria.

Utilización

La palabra clave synchronized puede aplicarse a métodos o bloques dentro de métodos. Cuando un método o bloque se declara como sincronizado, se obtiene un bloqueo sobre el objeto especificado, y se bloquea el acceso de otros hilos al código sincronizado hasta que se libere el bloqueo.

Syntax

Método sincronizado

public synchronized void synchronizedMethod() {
    // method code
}

Bloque sincronizado

public void method() {
    synchronized (object) {
        // synchronized code
    }
}
  • object: El objeto sobre el que sincronizar. Suele ser la instancia actual (this) o un objeto concreto.

Ejemplos

Ejemplo 1: Método sincronizado

public class Counter {
    private int count = 0;

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

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        Counter counter = new Counter();

        // Create multiple threads to increment the counter
        Thread t1 = new Thread(() -> counter.increment());
        Thread t2 = new Thread(() -> counter.increment());

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

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + counter.getCount());
    }
}

En este ejemplo, el método increment está sincronizado, lo que garantiza que sólo un hilo puede incrementar el contador a la vez, evitando condiciones de carrera.

Ejemplo 2: Bloque sincronizado

public class SynchronizedBlockExample {
    private final Object lock = new Object();
    private int count = 0;

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

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        SynchronizedBlockExample example = new SynchronizedBlockExample();

        // Create multiple threads to increment the counter
        Thread t1 = new Thread(() -> example.increment());
        Thread t2 = new Thread(() -> example.increment());

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

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + example.getCount());
    }
}

Este ejemplo utiliza un bloque sincronizado para controlar el acceso a la variable count. El objeto de bloqueo garantiza que sólo un hilo pueda ejecutar el bloque sincronizado a la vez.

Consejos y buenas prácticas

  • Minimizar el Código Sincronizado: Mantén los bloques sincronizados lo más cortos posible para reducir la contención y mejorar el rendimiento.
  • Utiliza Objetos Finales: Cuando utilices bloques sincronizados, utiliza objetos finales como bloqueos para garantizar la coherencia.
  • Evita la Sincronización Anidada: Los bloques sincronizados anidados pueden provocar bloqueos. Evítalos o utilízalos con precaución.
  • Utiliza Colecciones Concurrentes: Para una sincronización compleja, considera la posibilidad de utilizar colecciones concurrentes del paquete java.util.concurrent, como ConcurrentHashMap, que proporcionan sincronización incorporada.
  • Palabra clave volátil: Para las variables a las que acceden varios subprocesos pero que no requieren una sincronización compleja, considera la posibilidad de utilizar la palabra clave volatile para garantizar la visibilidad.
private volatile boolean flag;
  • Seguridad de la rosca: Asegúrate siempre de que los recursos compartidos están correctamente sincronizados para mantener la seguridad de los hilos y evitar la corrupción de datos.
  • Métodos estáticos sincronizados: Sincroniza los métodos estáticos para imponer el acceso sincronizado a nivel de clase, garantizando que sólo un hilo pueda ejecutar el método estático en todas las instancias.
public static synchronized void staticMethod() {
    // method code
}
  • Reentrada: Los bloqueos intrínsecos de Java son reentrantes, lo que significa que si un hilo tiene un bloqueo, puede adquirirlo de nuevo sin bloquearse.