Middle
O que é o bloco synchronized em Java e que problemas podem surgir ao usá-lo?
sobes.tech IA
Resposta da IA
O bloco synchronized em Java é usado para garantir a sincronização do acesso a um recurso compartilhado entre vários threads. Isso garante que apenas um thread possa executar o código dentro do bloco em qualquer momento.
Estrutura do bloco synchronized:
synchronized (objeto_monitor) {
// Seção crítica do código
// Operações com o recurso compartilhado
}
objeto_monitor: Qualquer objeto que atua como monitor (lock). Os threads que tentarem entrar em um blocosynchronizedcom o mesmo objeto monitor serão bloqueados até que o thread atual saia do bloco.
Problemas que podem surgir ao usar synchronized:
- Interbloqueio (Deadlock): Dois ou mais threads esperam liberar recursos que estão sendo utilizados por outros threads, levando o programa a ficar travado. Isso pode acontecer se os threads tentarem obter bloqueios em ordens diferentes.
- Redução de desempenho: A sincronização bloqueia a execução de outros threads que aguardam acesso ao monitor, o que pode desacelerar aplicações paralelas.
- Inaplicável em certos cenários: O bloco
synchronizedfornece acesso exclusivo. Em alguns casos, pode ser necessário um controle de acesso mais flexível (por exemplo, leitura por múltiplos threads simultaneamente, escrita por um único thread). - Complexidade na depuração: Problemas de sincronização podem ser pouco evidentes e difíceis de reproduzir e depurar.
Exemplo de interbloqueio:
class Resource {
private Object lock1 = new Object();
private Object lock2 = new Object();
public void method1(Resource other) {
synchronized (lock1) {
try {
Thread.sleep(100); // Simulação de trabalho
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " adquiriu lock1");
synchronized (other.lock2) {
System.out.println(Thread.currentThread().getName() + " adquiriu o lock2 do outro recurso");
}
}
}
public void method2(Resource other) {
synchronized (lock2) {
try {
Thread.sleep(100); // Simulação de trabalho
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " adquiriu lock2");
synchronized (other.lock1) {
System.out.println(Thread.currentThread().getName() + " adquiriu o lock1 do outro recurso");
}
}
}
}
public class DeadlockExample {
public static void main(String[] args) {
Resource r1 = new Resource();
Resource r2 = new Resource();
new Thread(() -> r1.method1(r2), "Thread-1").start();
new Thread(() -> r2.method2(r1), "Thread-2").start();
}
}
Neste exemplo, Thread-1 tenta obter lock1 em r1 e depois lock2 em r2. Thread-2 tenta obter lock2 em r2 e depois lock1 em r1. Se ambos obtiverem as primeiras bloqueios simultaneamente, ocorrerá um interbloqueio.