Problemas com synchronized

2 respostas
F

Olá.
Desculpem pelo tópico recorrente, mas pesquisei e não consegui encontrar alguma coisa aqui que me ajudasse a resolver isto.

Eu tenho uma classe InitiateThread, que pelo próprio nome diz, inicia as threads.

public class InitiateThread {
	public static void main(String args[]) {
		Thread thread1 = new MyThread();
		Thread thread2 = new MyThread();
		thread1.start();
		thread2.start();
	}

A classe MyThread

public class MyThread extends Thread {
	public void run() {
		StartService ss = new StartService();
		ss.saveInstance(serviço);
	}
}

A classe de negócio

public class StartService {
	public void saveInstance(Serviço serviço) {
       //Faz alguma coisa
       DBManager db = new DBManager();
       db.saveInstance(serviço);
	}
}

E por fim a classe que acessa o BD. Notem que o método saveInstance está sincronizado.

public class DBManager {
        public synchronized int saveInstance(Serviço serviço) {
            //1 - cria um ID global para o serviço em uma tabela global
    
            //2 - Utiliza o ID criado anteriormente para criar a instância do serviço em uma tabela local
	}
}

O problema que acontece é que quando eu executo, ele cria os dois IDs globais na tabela global, por exemplo 10 e 20, porém quando é pra gravar o serviço na tabela local (com o ID global), ele grava apenas um dos serviços (às vezes da thread1, às vezes da thread2) com o ID global 20 e depois tenta gravar o outro serviço com o ID 20 de novo, resultando em uma violção de chave primária no banco.
O synchronized não está no lugar certo?

Agradeço qualquer ajuda.

Obrigado.

2 Respostas

ViniGodoy

O bloco synchronized impede que duas threads acessem a mesma região DO MESMO OBJETO.

Como cada instância de StartService tem o seu próprio DBManager, cada thread pode percorrer seu próprio DBManager sossegada. Afinal, não se trata do mesmo objeto.

Para arrumar isso, faça o seguinte. Altere sua classe de negócio para:

public class StartService {
	DBManager db;

	public StartService(DBManager db) {
		this.db = db;
	}
	public void saveInstance(Serviço serviço) {
       //Faz alguma coisa       
       db.saveInstance(serviço);
	}
}

Sua classe de thread para:

public class MyThread implements Runnable {
	DBManager db;

	public MyThread (DBManager db) {
		this.db = db;
	}

	public void run() {
		StartService ss = new StartService();
		ss.saveInstance(db);
	}
}

E depois garanta que as duas threads receberão por parâmetro o mesmo DBManager:

public class InitiateThread {
	public static void main(String args[]) {
		DBManager db = new DBManager();
		Thread thread1 = new Thread(new MyThread(db));
		Thread thread2 = new Thread(new MyThread(dn));
		thread1.start();
		thread2.start();
	}
}
F

Deu certo. Muito obrigado :slight_smile:

Criado 4 de dezembro de 2007
Ultima resposta 4 de dez. de 2007
Respostas 2
Participantes 2