A palavra-chave synchronized
em Java é usada para garantir que um bloco de código ou um método seja acessado por apenas um thread por vez. Isso é essencial em ambientes multithread para evitar condições de corrida e garantir a integridade dos dados quando múltiplos threads podem acessar recursos compartilhados simultaneamente.
Uso da Palavra-chave synchronized
1.Método Synchronized: Ao declarar um método como synchronized
, você garante que apenas um thread possa executar esse método em um objeto específico ao mesmo tempo. O lock é obtido no objeto em que o método é chamado.
public class ContaBancaria {
private int saldo;
public synchronized void depositar(int valor) {
saldo += valor;
}
public synchronized void sacar(int valor) {
saldo -= valor;
}
public synchronized int getSaldo() {
return saldo;
}
}
2.Bloco Synchronized: Às vezes, você pode querer sincronizar apenas uma parte do código dentro de um método. Nesse caso, você usa um bloco synchronized
. Isso pode ser mais eficiente do que sincronizar o método inteiro, pois o lock é aplicado apenas à parte crítica do código.
public class ContaBancaria {
private int saldo;
public void depositar(int valor) {
synchronized (this) {
saldo += valor;
}
}
public void sacar(int valor) {
synchronized (this) {
saldo -= valor;
}
}
public int getSaldo() {
synchronized (this) {
return saldo;
}
}
}
3.Synchronized em Blocos com Objetos: Você também pode sincronizar em um objeto diferente, o que pode ser útil para evitar a sincronização de todo o método ou classe.
public class ContaBancaria {
private int saldo;
private final Object lock = new Object();
public void depositar(int valor) {
synchronized (lock) {
saldo += valor;
}
}
public void sacar(int valor) {
synchronized (lock) {
saldo -= valor;
}
}
public int getSaldo() {
synchronized (lock) {
return saldo;
}
}
}
Posts recentes
Comportamento e Regras
- Locks e Monitores: Quando um método ou bloco é sincronizado, ele adquire um lock no objeto especificado (ou na classe se o método for estático). Enquanto o lock está em uso, outros threads são impedidos de acessar qualquer método ou bloco sincronizado no mesmo objeto até que o lock seja liberado.
- Deadlock: Se não for usado com cuidado, a sincronização pode levar a deadlocks, onde dois ou mais threads estão bloqueados indefinidamente esperando uns pelos outros liberarem locks.
- Desempenho: O uso excessivo ou inadequado de
synchronized
pode levar a problemas de desempenho, pois pode criar contenção entre threads e reduzir a concorrência.
Exemplo de Uso
Aqui está um exemplo básico mostrando como a sincronização pode ser usada para evitar condições de corrida em um contador simples:
public class Contador {
private int count = 0;
public synchronized void incrementar() {
count++;
}
public synchronized int getCount() {
return count;
}
public static void main(String[] args) {
Contador contador = new Contador();
// Criar vários threads para incrementar o contador
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
contador.incrementar();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
contador.incrementar();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Contador: " + contador.getCount());
}
}
No exemplo acima, a sincronização garante que os métodos incrementar
e getCount
sejam acessados de forma segura por múltiplos threads, prevenindo problemas de concorrência e garantindo um resultado correto.