Nesse artigo vou falar sobre sincronização de métodos para evitar
problemas com o uso de threads. O uso de threads serve para agilizar a execução
de rotinas, porém devemos estar sempre atentos como o que pode ou não ser
acessado de modo paralelo por threads diferentes sem causar algum problema de consistência
nos dados.
Esse código abaixo mostra o acesso a um
método de uma classe de negócio qualquer. Não temos como garantir qual thread
vai acessar primeiro o método, e por mais que a thread1 acesse primeiro, não há
nenhuma garantia que ela vai concluir todo o seu trabalho antes que a thread2
também acesse o mesmo método.
public class SincronizacaoThreads {
public static void main( String[] args ) {
ClasseDeNegocio classeDeNegocio = new ClasseDeNegocio();
// Passando
a tarefa e o nome do Thread
Thread thread1 = new Thread( new Runnable() {
@Override
public void run() {
// executa
uma regra de negócio
classeDeNegocio.metodoA();
}
}, "thread
1" );
Thread thread2 = new Thread( new Runnable() {
@Override
public void run() {
// executa
uma regra de negócio
classeDeNegocio.metodoA();
}
}, "thread 2" );
thread1.start();
thread2.start();
}
}
public class ClasseDeNegocio {
public void metodoA() {
String nome = Thread.currentThread().getName();
System.out.println( nome + " entrando no metodoA" );
try {
Thread.sleep( 9000 );
} catch ( InterruptedException e ) {
e.printStackTrace();
}
System.out.println( nome + "
terminando execução do metodoA" );
System.out.println( nome + "
saindo do metodoA" );
}
}
Ao executar na minha máquina o
resultado foi:
Por isso, temos que tomar alguns cuidados ao usar threads. Digamos que
no metodoA chamado na classe de negócio houvesse acesso a dados para depois
processar alguma coisa e gravar no banco, já imaginou o problema? As duas
threads poderiam buscar os mesmos dados e fazer uma duplicação de informação, cálculos
errados, etc.
O que poderíamos fazer para evitar esses problemas?
· Sincronizar o acesso ao método
· Consultar os dados antes e depois passar
para cada thread os dados a serem trabalhados já divididos em dois conjuntos
distintos.
Qual o melhor a se fazer? Depende de cada caso! Pode haver casos que seja necessário as duas soluções, outros apenas uma delas basta. Sempre que puder, evite a sincronização, pois ela cria um gargalo, porém, não deixe de usar onde necessário, pois traria grandes transtornos.
Veja como
ficaria a sincronização do método:
public class ClasseDeNegocio {
public void metodoA() {
synchronized ( this ) {
String nome = Thread.currentThread().getName();
System.out.println( nome + " entrando no metodoA" );
try {
Thread.sleep( 9000 );
} catch ( InterruptedException e ) {
e.printStackTrace();
}
System.out.println( nome + "
terminando execução do metodoA" );
System.out.println( nome + "
saindo do metodoA" );
}
}
}
Como sincronizamos todo o método (pode haver casos que apenas um trecho precisa ser sincronizado) podemos usar o synchronized na declaração do método.
public class ClasseDeNegocio {
public synchronized void metodoA() {
String nome = Thread.currentThread().getName();
System.out.println( nome + " entrando no metodoA" );
try {
Thread.sleep( 9000 );
} catch ( InterruptedException e ) {
e.printStackTrace();
}
System.out.println( nome + "
terminando execução do metodoA" );
System.out.println( nome + "
saindo do metodoA" );
}
}
Veja como ficou o resultado da execução sincronizada:
O método passou a ser uma operação atômica, ou seja, a execução não pode ser interrompida na metade para que outra chamada entre nele. Espero que esse post tenha sido útil, até a próxima.
Nenhum comentário:
Postar um comentário