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
, comoConcurrentHashMap
, 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.