Erro na concorrência entre threads

5 respostas
N

Olá, estou com dificuldade num trabalho acadêmico com a seguinte proposta: fazer threads atravessarem de um lado para o outro da tela.
se vier uma thread da esquerda pra direta, entao uma trhead que vier da direita pra esquerda tem que esperar a primeira terninar.

criei um codigo da maneira mais facil de se entender. Mas está gerando um deadlock: quando uma thread atravessa pra um lado, a do lado oposto não começa atravessar quando a primeira termina, alguem consegue identificar onde esta o problema?

package CENARIO;

import java.awt.EventQueue;

@SuppressWarnings("serial")
public class Main extends JFrame {

	private JPanel contentPane;
	int limite=5;
	int iThread=0;
	ArrayList<classe> Thread = new ArrayList<classe> ();
	Semaphore direita= new Semaphore(limite);
	Semaphore esquerda= new Semaphore(limite);

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Main frame = new Main();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public Main() {
				
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(null);
		setContentPane(contentPane);
		
		JLabel lbCorda = new JLabel("--------------------cordaaaaaaaaaaaaaaa--------------------");
		lbCorda.setBounds(70, 84, 292, 14);
		contentPane.add(lbCorda);
		
		JButton btnE = new JButton("E");
		btnE.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				iThread++;
				classe 
				m = new classe("Thread " +
				iThread, esquerda, direita, limite);
				m.start();
			}
		});
		btnE.setBounds(10, 108, 51, 23);
		contentPane.add(btnE);
		
		JButton btnD = new JButton("D");
		btnD.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				iThread++;
				classe 
				m = new classe("Thread " +
				iThread, direita, esquerda, limite);
				m.start();
			}
		});
		btnD.setBounds(373, 108, 51, 23);
		contentPane.add(btnD);
		
	}
}
package THREADS;

import java.util.concurrent.Semaphore;

import javax.swing.JOptionPane;

public class classe extends Thread{
	String nome;
	Semaphore minhaDirecao;
	Semaphore direcaoOposta;
	int limite;	
	
	public void msg(Object x, int y){
		if(y==0){
			System.out.println(x);
		}
		if(y==1){
			JOptionPane.showMessageDialog(null, x, "Mensagem", JOptionPane.PLAIN_MESSAGE);
		}
		if(y==2){
			System.out.println(x);
			JOptionPane.showMessageDialog(null, x, "Mensagem", JOptionPane.PLAIN_MESSAGE);
		}
	}
	public classe(String nome, Semaphore minhaDirecao, Semaphore direcaoOposta, int limite){
		this.nome=nome;
		this.minhaDirecao=minhaDirecao;
		this.direcaoOposta=direcaoOposta;
		this.limite=limite;
	}

    public void animacao1(){    	
    	int tempo = (int) (Math.random() * 3500);
    	tempo+=500;
    	System.out.println(" " + tempo + " de velocidade");
    	try {
			sleep(tempo);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}    	
    }     

    public synchronized void conferir(){
		try {
			while (this.direcaoOposta.availablePermits()!=limite) {
				try {
					msg(nome+": Estou esperando, POIS VEM Thread DO OUTRO LADO",0);
					this.wait();
				} catch (InterruptedException e) {}
			}
			msg(nome+": JÁ VERIFIQUEM, AGORA VOU",0);
			this.minhaDirecao.acquire();
			this.notifyAll();	
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally{
			if(this.minhaDirecao.availablePermits()==0){
				msg(nome+": Vou esperar pra nao arrebebtar a corda",0);
			}
			animacao1();
			msg(nome+": ------------------Já FUI!!!",0);
			this.minhaDirecao.release();
			this.notifyAll();		
		}
    }
	public void run(){
		conferir();
	}
}

5 Respostas

Roselito_Favero_da_S

Experimente mandar imprimir a pilha dentro deste catch

try {  
                    msg(nome+": Estou esperando, POIS VEM Thread DO OUTRO LADO",0);  
                    this.wait();  
                } catch (InterruptedException e) {} <-----------

pois pode estar com algum erro mais difícil de detectar.

N

modifiquei e nada

ele não apresenta exceções

parece que ele não está conseguindo ler o notifyAll que coloquei daí ele continua esperando pelo comando pro resto da vida

N

Consegui!!!

package THREADS;

import java.util.concurrent.Semaphore;

import javax.swing.JOptionPane;

public class classe extends Thread{
	String nome;
	Semaphore minhaDirecao;
	Semaphore direcaoOposta;
	int limite;	
	
	public void msg(Object x, int y){
		if(y==0){
			System.out.println(x);
		}
		if(y==1){
			JOptionPane.showMessageDialog(null, x, "Mensagem", JOptionPane.PLAIN_MESSAGE);
		}
		if(y==2){
			System.out.println(x);
			JOptionPane.showMessageDialog(null, x, "Mensagem", JOptionPane.PLAIN_MESSAGE);
		}
	}
	public classe(String nome, Semaphore minhaDirecao, Semaphore direcaoOposta, int limite){
		this.nome=nome;
		synchronized (this) {
			this.minhaDirecao=minhaDirecao;
		}
		
		synchronized (this){
			this.direcaoOposta=direcaoOposta;
		}

		this.limite=limite;
	}

    public void animacao1(){    	
    	int tempo = (int) (Math.random() * 3500);
    	tempo+=500;
    	System.out.println(" " + tempo + " de velocidade");
    	try {
			sleep(tempo);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}    	
    }     

    public void conferir(){
		try {
			synchronized (this.direcaoOposta){
			while (this.direcaoOposta.availablePermits()!=limite) {
				try {
					msg(nome+": Estou esperando, POIS VEM Thread DO OUTRO LADO",0);
					this.direcaoOposta.wait();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
			msg(nome+": JÁ VERIFIQUEM, AGORA VOU",0);
			this.minhaDirecao.acquire();
			this.direcaoOposta.notifyAll();	
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally{
			if(this.minhaDirecao.availablePermits()==0){
				msg(nome+": Vou esperar pra nao arrebebtar a corda",0);
			}
			animacao1();
			msg(nome+": ------------------Já FUI!!!",0);
			synchronized (this.minhaDirecao) {
				this.minhaDirecao.release();
				this.minhaDirecao.notifyAll();			
			}
			
		}
    }
	public void run(){
		conferir();
	}
}
package CENARIO;

import java.awt.EventQueue;
import java.util.concurrent.Semaphore;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import THREADS.classe;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

@SuppressWarnings("serial")
public class Main extends JFrame {

	private JPanel contentPane;
	int limite=5;
	int iThread=0;
	Semaphore direita= new Semaphore(limite);
	Semaphore esquerda= new Semaphore(limite);

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Main frame = new Main();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public Main() {
				
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(null);
		setContentPane(contentPane);
		
		JLabel lbCorda = new JLabel("--------------------cordaaaaaaaaaaaaaaa--------------------");
		lbCorda.setBounds(70, 84, 292, 14);
		contentPane.add(lbCorda);
		
		JButton btnE = new JButton("E");
		btnE.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				iThread++;
				classe 
				m = new classe("Thread " +
				iThread, esquerda, direita, limite);
				m.start();
			}
		});
		btnE.setBounds(10, 108, 51, 23);
		contentPane.add(btnE);
		
		JButton btnD = new JButton("D");
		btnD.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				iThread++;
				classe 
				m = new classe("Thread " +
				iThread, direita, esquerda, limite);
				m.start();
			}
		});
		btnD.setBounds(373, 108, 51, 23);
		contentPane.add(btnD);
		
	}
}
Roselito_Favero_da_S

Que bom. Mas destaca sua solução e o que estava errado pra gente.

N

ok,

eu nao estava sabendo usar o synchronized corretamente

no meu codigo, os recursos compartilhados eram so semaforos direita e esquerda.

cada thread entendia eles como minha direção e direção oposta, de acordo com a direção da thread
por exemplo as thread que vão para a direita, entende o semaforo direita como minhaDireção e o semaforo esquerda como direçãoOposta

o que eu estava fazendo de errado era colocar o synchronized, wait e notify como comandos das threads. Desse jeito, quando uma thread dormia e outra fazia um notify, ela estava apenas avisando a si mesma que tinha liberado o synchronized. quem tava dormindo nao recebia a noticia e continuava dormindo

a correção foi colocar o synchronized, o wait e o notify como comandos dos recursos compartilhados
primeiro sincronizei a direçãoOposta e a mandei esperar as threads do outro lado que ja tinham iniciado
e quando uma thread do outro lado finalizava, eu sinchronizava a sua direção e mandava ela avisar tudo o que acontecua com a sua direção (que é a direção oposta da thread que tava dormindo).
daí quaqndo a direção liberava, a que tava dormindo voltava à ativa

espero ter conseguido explicar. pq como eh novo pra mim eh meio confuso ainda.

Mas eh muito maneiro! programação paralela é muito mais empolgante que a programação sequencial

Criado 24 de novembro de 2013
Ultima resposta 24 de nov. de 2013
Respostas 5
Participantes 2