Blz pessoal,
recentemente estava com algumas duvidas na utilização dos métodos wait() e notify() para a manipulação de Thread’s juntamente com o modificador synchronized, então resolvi estudar um pouco e criar o famoso programa Produtor / Consumidor, é claro utilizando o recurso de Thread’s.
Esclarecimentos:
Há um tempo atrás eu imaginava que poderia executar duas Threads (Thead A e Thread B), e dizer assim: “A agora você para (utilizando wait()) e B comece a trabalhar (utilizando notify()) fora de um contexto sincronizado”, tão logo descobri que, para que os métodos wait() e notify() funcionem eles devem sempre estar dentro de um bloco synchronized, no inicio tive muitos problemas de mandar uma Thread parar (wait()), o programa ficava eternamente em espera(famoso dead lock) ou até mesmo lançava exceptions ILegalMonitorExceptions.
Fiz algumas loucuras do tipo, passar para o construtor da Thread A a Thread B e vice-versa e aplicar wait e notify na esperança de parar a Thead e em seguida coloca-la em estado de execução, resultado: consegui construir o caos, enumeras exceptions e travamento de maquina.
Em fim, é com os erros que aprendemos mas procure não errar tanto. hahahah. Como recomendação executem esse código normalmente e em seguinda adicione alguns breakpoints para uma melhor compreensão com o modo debug.
Vou postar o código aqui para quem tiver duvidas na utilização do wait() bem como notify(), tenham um exemplo para se embasar em codificações utilizando Thread’s.
Creio que após o estudo desse código, a construção de Threads tornará-se mais amigável.
Considerações
Observe que nas classes Produtor e Consumidor onde há o comentário (número um) contem a chamada do método wait() logo na inicialização, isso foi necessário pois devemos considerar que, de uma pilha com tamanho finito, não podemos retirar elementos caso a mesmo esteja vazia, em contra partida não podemos adicionar elementos se a mesma já se encontra totalmente cheia.
Desse modo, quando o loop da classe Start é inciado existe uma checagem para verificar se a pilha está fazia (número dois), caso esteja o Produtor é notificado e começa a produção, ao termino da produção, a execução vai para a próxima linha (número três). Então é feita novamente uma checagem para verificar se a pilha está cheia, sendo verdadeiro o Consumidor é notificado e começa a retirada da pilha, sendo assim os próximos processo são executados sucintamente.
Obs
Tal código foi criado para expressar a codificação de Threads com a utilização de seus métodos de controle. Vale ressaltar que as classes abaixo são meramente ilustrativas sendo que para criar
um verdadeiro Produtor / Consumidor é necessário mais controle e uma melhor elaboração para a codificação do problema.
Classe Produtor
[code]
package br.com.exe;
public class Produtor implements Runnable {
Pilha pilha;
int bufferSize;
Produtor(Pilha pilha, int bufferSize) {
this.pilha = pilha;
this.bufferSize = bufferSize;
}
public void run() {
while (true) {
synchronized (this) {
try {
wait(); // -----> 1
} catch (InterruptedException e) {
e.printStackTrace();
}
while (pilha.get() >= 0 && pilha.get() <= (bufferSize-1)) {
pilha.put(pilha.get() + 1);
System.out.println("Produzindo -> " + pilha.get());
}
}
}
}
public void init() {
new Thread(this, "Produtor").start();
}
}[/code]
Classe Consumidor
[code]package br.com.exe;
public class Consumidor implements Runnable {
Pilha pilha;
public Consumidor(Pilha pilha) {
this.pilha = pilha;
}
public void run() {
while (true) {
synchronized (this) {
try {
wait(); // ---------------- 1
} catch (InterruptedException e) {
e.printStackTrace();
}
while (pilha.get() != 0) {
System.out.println("Consumindo -> " + pilha.get());
pilha.put(pilha.get() - 1);
}
}
}
}
public void init() {
new Thread(this, "Consumidor").start();
}
}[/code]
Classe Pilha
[code]
package br.com.exe;
public class Pilha {
int n = 0;
synchronized int get(){
return n;
}
synchronized int put(int n){
this.n = n;
return this.n;
}
}[/code]
Classe Start
[code]
package br.com.exe;
public class Start {
public static void main(String[] args) {
new Runnable() {
@Override
public void run() {
final int bufferSize = 10;
Pilha pilha = new Pilha();
Produtor p = new Produtor(pilha, bufferSize);
Consumidor c = new Consumidor(pilha);
p.init();
c.init();
while (true) {
if (pilha.get() == 0) { // -----------> 2
synchronized (p) {
System.out.println("************************* Incializa Produção *************************");
p.notify();
}
}
if (pilha.get() == bufferSize) { // -------------> 3
synchronized (c) {
System.out.println("************************* Incializa Consumo *************************");
c.notify();
}
}
}
}
}.run();
}
}[/code]