[Resolvido] Dúvida com sincronização de threads

Galera é o seguinte, tenho as seguintes classes, porém depois de um tempo aparentemente ficam todas as threads suspensas e me parece que so a relativa ao filosofo 4 fica ativa, sendo assim ela produz somente resultados relativos a esse filósofo.

class FilosofoGlutao implements Runnable{
	boolean cond = false;
	final int N = 5; // são cinco filosofos e cinco garfos...
	List <Garfo> garfos; // garfos disponíveis 0, 1, 2, 3 e 4
	int filosofo;
	FilosofoGlutao (List <Garfo>gs, int fil){
		garfos = gs;
		filosofo = fil;

	}


	
	public void run(){
		for (int i=0; i<5; i++){
			// pensa ...
			pensaMuito(filosofo);
			try{
			// pega garfo da esquerda
			pegaGarfo(/*posiçao*/filosofo, /*dono*/filosofo);
			// pega garfo da direita
			pegaGarfo(/*posiçao*/(filosofo+1)%N, /*dono*/filosofo);
			// fatura o espaguete
			comeEspaguete(filosofo);
			// larga o garfo da esquerda
			largaGarfo(/*posiçao*/filosofo, /*dono*/filosofo);
			// larga o garfo da direita
			largaGarfo(/*posiçao*/(filosofo+1)%N, /*dono*/filosofo);
			}catch (InterruptedException e) {
				System.out.print("Processamento da impressora interrompido.");
			}
		}
	}
	
	
	
	private void pensaMuito(int fil){
		switch (fil) {
			case 0: // filosofo 0 pensa por 1000 ms...
				try{ 
					System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
					Thread.sleep(500);}
				catch (InterruptedException e){}
			case 1: // filosofo 1 pensa por 2000 ms...
				try{ 
					System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
					Thread.sleep(1000);}
				catch (InterruptedException e){}
			case 2: // filosofo 1 pensa por 3000 ms...
				try{ 
					System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
					Thread.sleep(1500);}
				catch (InterruptedException e){}
			case 3: // filosofo 1 pensa por 4000 ms...
				try{
					System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
					Thread.sleep(2000);}
				catch (InterruptedException e){}
			case 4: // filosofo 1 pensa por 5000 ms...
				try{
					System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
					Thread.sleep(2500);}
				catch (InterruptedException e){}
		}		
	}

	private synchronized void pegaGarfo(int pos, int dono) {
		while(((Garfo)garfos.get(pos)).getEstadoGarfo()){
			try{
			wait();
			}catch (InterruptedException e) { }
			}
			System.out.println("++>"+Thread.currentThread().getName()+" PEGA GARFO "+ pos);			
			((Garfo)garfos.get(pos)).setEstadoGarfo(true); // pega garfo
			((Garfo)garfos.get(pos)).setDonoGarfo(dono); // pega garfo
			notifyAll();
		//}
	}
	
	private synchronized void largaGarfo(int pos, int dono) throws InterruptedException{
			System.out.println("-->"+Thread.currentThread().getName()+" LARGA GARFO "+ pos);
			((Garfo)garfos.get(pos)).setEstadoGarfo(false); // garfo liberado
			((Garfo)garfos.get(pos)).setDonoGarfo(-1); // garfo sem dono

	//	}
	}
	
	private void comeEspaguete(int fil){
		// se ambos os garfos estiverem reservados pelo
		// filosofo "fil", então ele come espaguete...
		// Testar a sua solução de proteção, comente o if, deixando apenas o 
		// seu conteúdo liberado
		if (((Garfo)garfos.get(fil)).getEstadoGarfo() &&
			((Garfo)garfos.get((fil+1)%N)).getEstadoGarfo() &&
			((Garfo)garfos.get(fil)).getDonoGarfo()==fil &&
			((Garfo)garfos.get((fil+1)%N)).getDonoGarfo()==fil){
			System.out.println("@@>"+Thread.currentThread().getName()+" COME ESPAGUETE");
			try{ Thread.sleep(5000);}
			catch (InterruptedException e){}
			}





public class ProblemaDosFilosofosGlutoes{
	public static void main(String args[]){
		// cria os grafos (coleção de 5 garfos)
		List<Garfo>garfos = new ArrayList<Garfo>();
		for (int i = 0; i<=4; i++){
			Garfo garfo = new Garfo(i);
			garfos.add(i,garfo);
		}
		// cria a thread do filosofo 0
		FilosofoGlutao r0 = new FilosofoGlutao(garfos, 0);
		Thread f0 = new Thread(r0);
		// cria a thread do filosofo 1
		FilosofoGlutao r1 = new FilosofoGlutao(garfos, 1);
		Thread f1 = new Thread(r1);
		// cria a thread do filosofo 2
		FilosofoGlutao r2 = new FilosofoGlutao(garfos, 2);
		Thread f2 = new Thread(r2);
		// cria a thread do filosofo 3
		FilosofoGlutao r3 = new FilosofoGlutao(garfos, 3);
		Thread f3 = new Thread(r3);
		// cria a thread do filosofo 4
		FilosofoGlutao r4 = new FilosofoGlutao(garfos, 4);
		Thread f4 = new Thread(r4);		
		
		// nomeia as threads
		f0.setName("F0");
		f1.setName("F1");
		f2.setName("F2");
		f3.setName("F3");
		f4.setName("F4");
		
		// manda as threads pra fila de pronto
		f0.start();
		f1.start();
		f2.start();
		f3.start();
		f4.start();
	}

Estou com um problema parecido utilizando lock/condition.

Oi,

A principio já sei onde está o problema. Só queria comprovar antes de falar um besteira rsrs…

Poderia passar a classe Garfo ?

Tchauzin!

Classe Garfo:

package filosofos;

public class Garfo{
	private int idGarfo;
	private boolean estadoGarfo;
	private int dono;
	
	public Garfo(int id){
		idGarfo = id;
		estadoGarfo = false; // desocupado		
		dono = -1; // sem dono
	}
	
	public int getIdGarfo(){
		return idGarfo;
	}
	
	public void setIdGarfo(int g){
		idGarfo = g;
	}
	
	public int getDonoGarfo(){
		return dono;
	}
	
	public void setDonoGarfo(int d){
		dono = d;	
	}
	
	public boolean getEstadoGarfo(){
		return estadoGarfo;
	}
	
	public void setEstadoGarfo(boolean ocupado){
		estadoGarfo = ocupado;
	}
}

Oi,

É realmente o que eu pensava. Presta atenção no código abaixo:

private synchronized void pegaGarfo(int pos, int dono) { while(((Garfo)garfos.get(pos)).getEstadoGarfo()){ try{ System.out.println("ENTROU EM WAIT "+Thread.currentThread().getName()); wait(); System.out.println("SAIU EM WAIT "+Thread.currentThread().getName()); }catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("++>"+Thread.currentThread().getName()+" PEGA GARFO "+ pos); ((Garfo)garfos.get(pos)).setEstadoGarfo(true); // pega garfo ((Garfo)garfos.get(pos)).setDonoGarfo(dono); // pega garfo notifyAll(); //} }

Agora presta atenção na saída dos Sysout:

!!>F0 PENSA !!>F2 PENSA !!>F1 PENSA !!>F4 PENSA !!>F3 PENSA !!>F0 PENSA !!>F1 PENSA !!>F2 PENSA !!>F0 PENSA !!>F3 PENSA !!>F1 PENSA ++>F4 PEGA GARFO 4 ++>F4 PEGA GARFO 0 @@>F4 COME ESPAGUETE !!>F0 PENSA !!>F2 PENSA ++>F3 PEGA GARFO 3 !!>F1 PENSA ENTROU EM WAIT F3 !!>F0 PENSA ++>F2 PEGA GARFO 2 ENTROU EM WAIT F2 ++>F1 PEGA GARFO 1 ENTROU EM WAIT F1 -->F4 LARGA GARFO 4 -->F4 LARGA GARFO 0 !!>F4 PENSA ++>F0 PEGA GARFO 0 ENTROU EM WAIT F0 ++>F4 PEGA GARFO 4 ENTROU EM WAIT F4

Ou seja, quando a Thread F3 entrou em Wait() as outras F1, F2 ,F0 e F4 continuaram seu processamento. Porém quando todas entraram em WAIT(), não existe mais o que fazer. Quem irá notifica-las?

Tchauzin!

Lina, e como podemos resolver o problema?

O notifyAll() não deveria liberar as threads do wait()?

Oi,

Na verdade, eu precisaria saber qual é o teu Objetivo… Ou melhor, quando a Thread deverá entrar em Wait e por qual condição ela deverá sair do Wait.

Tchauzin!

Oi,

Na verdade não. Estamos falando de conceitos MultiThreads.

As quatro Threads precisam ter um objeto em comum. Sem esse objeto, as Threads F0, F1, F2 e F3 (por exemplo) não fazem nem ideia de que a Thread F4 existe.

O que pode-se fazer é:

[code]public class ProblemaDosFilosofosGlutoes{
public static void main(String args[]){
Object lock = new Object(); // OBJETO EM COMUM
// cria os grafos (coleção de 5 garfos)
Listgarfos = new ArrayList();
for (int i = 0; i<=4; i++){
Garfo garfo = new Garfo(i);
garfos.add(i,garfo);
}
// cria a thread do filosofo 0
FilosofoGlutao r0 = new FilosofoGlutao(garfos, 0, lock); // Usando esse objeto.
Thread f0 = new Thread(r0);
// cria a thread do filosofo 1
FilosofoGlutao r1 = new FilosofoGlutao(garfos, 1, lock); // Usando esse objeto.
Thread f1 = new Thread(r1);
// cria a thread do filosofo 2
FilosofoGlutao r2 = new FilosofoGlutao(garfos, 2, lock); // Usando esse objeto.
Thread f2 = new Thread(r2);
// cria a thread do filosofo 3
FilosofoGlutao r3 = new FilosofoGlutao(garfos, 3, lock); // Usando esse objeto.
Thread f3 = new Thread(r3);
// cria a thread do filosofo 4
FilosofoGlutao r4 = new FilosofoGlutao(garfos, 4, lock); // Usando esse objeto.
Thread f4 = new Thread(r4);

	// nomeia as threads
	f0.setName("F0");
	f1.setName("F1");
	f2.setName("F2");
	f3.setName("F3");
	f4.setName("F4");
	
	// manda as threads pra fila de pronto
	f0.start();
	f1.start();
	f2.start();
	f3.start();
	f4.start();
}

}[/code]

Na classe FilosofoGlutao, utiliza-se esse objeto para sincronizar, aguardar e notificar:

[code]

/**
Apenas para mostrar como atribui-lo no construtor.
*/

Object
lock = null;

FilosofoGlutao (List <Garfo>gs, int fil, Object lock){
	garfos = gs;
	filosofo = fil;
	this.lock	=	lock;
}[/code]

E finalmente o método:

[code]private synchronized void pegaGarfo(int pos, int dono) {
	while(((Garfo)garfos.get(pos)).getEstadoGarfo()){
		try{

			synchronized (this.lock)
			{
				this.lock.wait();
			}			
		}catch (InterruptedException e) { e.printStackTrace(); }
		}
		System.out.println("++>"+Thread.currentThread().getName()+" PEGA GARFO "+ pos);			
		((Garfo)garfos.get(pos)).setEstadoGarfo(true); // pega garfo
		((Garfo)garfos.get(pos)).setDonoGarfo(dono); // pega garfo
		
		synchronized (this.lock)
		{
			this.lock.notifyAll();
		}
}[/code]

Só mais uma observação… No run da Thread principal, retire o for até 5 e coloque:

[code]public void run(){
	while (!Thread.currentThread().isInterrupted()){
		// pensa ...
		pensaMuito(filosofo);
		try{
		// pega garfo da esquerda
		pegaGarfo(/*posiçao*/filosofo, /*dono*/filosofo);
		// pega garfo da direita
		pegaGarfo(/*posiçao*/(filosofo+1)%N, /*dono*/filosofo);
		// fatura o espaguete
		comeEspaguete(filosofo);
		// larga o garfo da esquerda
		largaGarfo(/*posiçao*/filosofo, /*dono*/filosofo);
		// larga o garfo da direita
		largaGarfo(/*posiçao*/(filosofo+1)%N, /*dono*/filosofo);
		}catch (InterruptedException e) {
			System.out.print("Processamento da impressora interrompido.");
		}
	}
}[/code]

Tchauzin!

Oi lina,

O código continua agarrando no F4.

!!>F1 PENSA !!>F3 PENSA !!>F2 PENSA !!>F0 PENSA !!>F4 PENSA !!>F0 PENSA !!>F1 PENSA !!>F0 PENSA !!>F2 PENSA !!>F3 PENSA !!>F1 PENSA ++>F4 PEGA GARFO 4 ++>F4 PEGA GARFO 0 @@>F4 COME ESPAGUETE !!>F0 PENSA !!>F2 PENSA !!>F1 PENSA ++>F3 PEGA GARFO 3 !!>F0 PENSA ++>F2 PEGA GARFO 2 ++>F1 PEGA GARFO 1 -->F4 LARGA GARFO 4 -->F4 LARGA GARFO 0 !!>F4 PENSA ++>F4 PEGA GARFO 4 ++>F4 PEGA GARFO 0 ++>F0 PEGA GARFO 0 @@>F4 COME ESPAGUETE -->F4 LARGA GARFO 4 -->F4 LARGA GARFO 0 !!>F4 PENSA ++>F4 PEGA GARFO 4 ++>F4 PEGA GARFO 0 @@>F4 COME ESPAGUETE -->F4 LARGA GARFO 4 -->F4 LARGA GARFO 0 !!>F4 PENSA ++>F4 PEGA GARFO 4 ++>F4 PEGA GARFO 0 @@>F4 COME ESPAGUETE -->F4 LARGA GARFO 4 -->F4 LARGA GARFO 0 !!>F4 PENSA ++>F4 PEGA GARFO 4 ++>F4 PEGA GARFO 0 @@>F4 COME ESPAGUETE -->F4 LARGA GARFO 4 -->F4 LARGA GARFO 0 !!>F4 PENSA ++>F4 PEGA GARFO 4 ++>F4 PEGA GARFO 0 @@>F4 COME ESPAGUETE -->F4 LARGA GARFO 4 -->F4 LARGA GARFO 0 !!>F4 PENSA ++>F4 PEGA GARFO 4 ++>F4 PEGA GARFO 0 @@>F4 COME ESPAGUETE -->F4 LARGA GARFO 4 -->F4 LARGA GARFO 0 !!>F4 PENSA ++>F4 PEGA GARFO 4 ++>F4 PEGA GARFO 0 @@>F4 COME ESPAGUETE

 while (!Thread.currentThread().isInterrupted()){   

Quando entra nesse while?

Oi,

Assim:

public void run(){ while (!Thread.currentThread().isInterrupted()){ // pensa ... pensaMuito(filosofo); try{ // pega garfo da esquerda pegaGarfo(/*posiçao*/filosofo, /*dono*/filosofo); // pega garfo da direita pegaGarfo(/*posiçao*/(filosofo+1)%N, /*dono*/filosofo); // fatura o espaguete comeEspaguete(filosofo); // larga o garfo da esquerda largaGarfo(/*posiçao*/filosofo, /*dono*/filosofo); // larga o garfo da direita largaGarfo(/*posiçao*/(filosofo+1)%N, /*dono*/filosofo); }catch (InterruptedException e) { System.out.print("Processamento da impressora interrompido."); } } }

Tchauzin!

Que é ai tudo bem.
Mas continua travando no F4.

[quote=douglas999]Que é ai tudo bem.
Mas continua travando no F4.[/quote]

Oi,

Falta alguma coisa ainda. Posta o código inteiro. Já apaguei do meu eclipse…

Tchauzin!

classe Garfo:

[code]package jantarFilosofico;

public class Garfo {

	private int idGarfo;
	private boolean estadoGarfo;
	private int dono;
	
	public Garfo(int id){
		idGarfo = id;
		estadoGarfo = false; // desocupado		
		dono = -1; // sem dono
	}
	
	public int getIdGarfo(){
		return idGarfo;
	}
	
	public void setIdGarfo(int g){
		idGarfo = g;
	}
	
	public int getDonoGarfo(){
		return dono;
	}
	
	public void setDonoGarfo(int d){
		dono = d;	
	}
	
	public boolean getEstadoGarfo(){
		return estadoGarfo;
	}
	
	public void setEstadoGarfo(boolean ocupado){
		estadoGarfo = ocupado;
	}

}

[/code]

[code]package jantarFilosofico;

import java.util.List;
import java.lang.*;

class FilosofoGlutao implements Runnable{
// boolean cond = false;

Object lock = null;
FilosofoGlutao (List <Garfo>gs, int fil, Object lock){   
    garfos = gs;   
    filosofo = fil;   
    this.lock   =   lock;   
}

final int N = 5; // são cinco filosofos e cinco garfos...
List <Garfo> garfos; // garfos disponíveis 0, 1, 2, 3 e 4
int filosofo;
FilosofoGlutao (List <Garfo>gs, int fil){
	garfos = gs;
	filosofo = fil;

}

public void run(){
	while (!Thread.currentThread().isInterrupted()){
		// pensa ...
		pensaMuito(filosofo);
		try{
		// pega garfo da esquerda
		pegaGarfo(/*posiçao*/filosofo, /*dono*/filosofo);
		// pega garfo da direita
		pegaGarfo(/*posiçao*/(filosofo+1)%N, /*dono*/filosofo);
		// fatura o espaguete
		comeEspaguete(filosofo);
		// larga o garfo da esquerda
		largaGarfo(/*posiçao*/filosofo, /*dono*/filosofo);
		// larga o garfo da direita
		largaGarfo(/*posiçao*/(filosofo+1)%N, /*dono*/filosofo);
		}catch (InterruptedException e) {
			System.out.print("Processamento da impressora interrompido.");
		}
	}
}

// public synchronized void setCond(boolean cond) {
// this.cond = cond;
//
// // Caso pausado seja definido como false, acordamos a thread e pedimos
// // para ela verificar sua condição. Nesse caso, sabemos que a thread
// // acordará, mas no caso de uma condição com várias alternativas, nem
// // sempre isso seria verdadeiro.
// notifyAll();
// }

private void pensaMuito(int fil){
	switch (fil) {
		case 0: // filosofo 0 pensa por 1000 ms...
			try{ 
				System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
				Thread.sleep(500);}
			catch (InterruptedException e){}
		case 1: // filosofo 1 pensa por 2000 ms...
			try{ 
				System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
				Thread.sleep(1000);}
			catch (InterruptedException e){}
		case 2: // filosofo 1 pensa por 3000 ms...
			try{ 
				System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
				Thread.sleep(1500);}
			catch (InterruptedException e){}
		case 3: // filosofo 1 pensa por 4000 ms...
			try{
				System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
				Thread.sleep(2000);}
			catch (InterruptedException e){}
		case 4: // filosofo 1 pensa por 5000 ms...
			try{
				System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
				Thread.sleep(2500);}
			catch (InterruptedException e){}
	}		
}

private synchronized void pegaGarfo(int pos, int dono){
	while(((Garfo)garfos.get(pos)).getEstadoGarfo()){
		 try{   
			  
                synchronized (this.lock)   
                {   
                    this.lock.wait();   
                }             
            }catch (InterruptedException e) { e.printStackTrace(); }   
            }   

		System.out.println("++>"+Thread.currentThread().getName()+" PEGA GARFO "+ pos);			
		((Garfo)garfos.get(pos)).setEstadoGarfo(true); // pega garfo
		((Garfo)garfos.get(pos)).setDonoGarfo(dono); // pega garfo
		
		synchronized (this.lock)   
        {   
            this.lock.notifyAll();   
        }   
}

private synchronized void largaGarfo(int pos, int dono) throws InterruptedException{
		System.out.println("-->"+Thread.currentThread().getName()+" LARGA GARFO "+ pos);
		((Garfo)garfos.get(pos)).setEstadoGarfo(false); // garfo liberado
		((Garfo)garfos.get(pos)).setDonoGarfo(-1); // garfo sem dono
//	}
}

private void comeEspaguete(int fil){
	// se ambos os garfos estiverem reservados pelo
	// filosofo "fil", então ele come espaguete...
	// Testar a sua solução de proteção, comente o if, deixando apenas o 
	// seu conteúdo liberado
	if (((Garfo)garfos.get(fil)).getEstadoGarfo() &&
		((Garfo)garfos.get((fil+1)%N)).getEstadoGarfo() &&
		((Garfo)garfos.get(fil)).getDonoGarfo()==fil &&
		((Garfo)garfos.get((fil+1)%N)).getDonoGarfo()==fil){
		System.out.println("@@>"+Thread.currentThread().getName()+" COME ESPAGUETE");
		try{ Thread.sleep(5000);}
		catch (InterruptedException e){}
		}
}	

}[/code]

[code]package jantarFilosofico;

import java.util.ArrayList;
import java.util.List;

import jantarFilosofico.Garfo;

public class JantarMain {

public static void main(String[] args) {

	
	Object lock = new Object(); //objeto em comum
	// cria os grafos (coleção de 5 garfos)
			List<Garfo>garfos = new ArrayList<Garfo>();
			for (int i = 0; i<=4; i++){
				Garfo garfo = new Garfo(i);
				garfos.add(i,garfo);
			}
			// cria a thread do filosofo 0
			FilosofoGlutao r0 = new FilosofoGlutao(garfos, 0, lock);
			Thread f0 = new Thread(r0);
			// cria a thread do filosofo 1
			FilosofoGlutao r1 = new FilosofoGlutao(garfos, 1, lock);
			Thread f1 = new Thread(r1);
			// cria a thread do filosofo 2
			FilosofoGlutao r2 = new FilosofoGlutao(garfos, 2, lock);
			Thread f2 = new Thread(r2);
			// cria a thread do filosofo 3
			FilosofoGlutao r3 = new FilosofoGlutao(garfos, 3, lock);
			Thread f3 = new Thread(r3);
			// cria a thread do filosofo 4
			FilosofoGlutao r4 = new FilosofoGlutao(garfos, 4, lock);
			Thread f4 = new Thread(r4);		
			
		
			
			// nomeia as threads
			f0.setName("F0");
			f1.setName("F1");
			f2.setName("F2");
			f3.setName("F3");
			f4.setName("F4");
			
			// manda as threads pra fila de pronto
			f0.start();
			f1.start();
			f2.start();
			f3.start();
			f4.start();
		}

}
[/code]

private void pensaMuito(int fil){ switch (fil) { case 0: // filosofo 0 pensa por 1000 ms... try{ System.out.println("!!>"+Thread.currentThread().getName()+" PENSA"); Thread.sleep(500);} catch (InterruptedException e){} case 1: // filosofo 1 pensa por 2000 ms... try{ System.out.println("!!>"+Thread.currentThread().getName()+" PENSA"); Thread.sleep(1000);} catch (InterruptedException e){} case 2: // filosofo 1 pensa por 3000 ms... try{ System.out.println("!!>"+Thread.currentThread().getName()+" PENSA"); Thread.sleep(1500);} catch (InterruptedException e){} case 3: // filosofo 1 pensa por 4000 ms... try{ System.out.println("!!>"+Thread.currentThread().getName()+" PENSA"); Thread.sleep(2000);} catch (InterruptedException e){} case 4: // filosofo 1 pensa por 5000 ms... try{ System.out.println("!!>"+Thread.currentThread().getName()+" PENSA"); Thread.sleep(2500);} catch (InterruptedException e){} } }

fica melhor assim não?

[code]private int[] tempoFilosofos = {500, 1000, 1500, 2000, 2500};

private void pensaMuito(int fil){
if ((fil >= 0) || (fil < tempoFilosofos.Length)){
System.out.println("!!>"+Thread.currentThread().getName()+" PENSA");
Thread.sleep(tempoFilosofos[fil]);
}
}
[/code]

Galera depois de bastante quebrar a cabeça, eu e o Douglas conseguimos resolver o problema usando o synchronized, próximo passo será o desenvolvimento usando o método de semáforo, OBRIGADO PELA AJUDA DE VOCES.

E qual foi a solução? Seria interessante ter a solução no tópico para evitar a criação de um novo.