Dúvida Threads [Resolvido]

Tenho duas dúvidas sobre Threads:

  1. A primeira pergunta é: Qual a melhor forma de se usar Threads?

Conheço três formas:

 Thread t = new Thread();
 
 MinhaClasse extends Threads

 MinhaClasse implements Runnable

A primeira cria um objeto da classe Thread, contudo eu não sei usar assim, pq naum tenho como especificar o que eu quero que ela faça (método run), certo?

A segunda, eu estendo da Classe Thread e digo o que o quero que fazer sobrescrevendo o método run()

A terceira eu implemento a interface Runnable, que me obriga a implementar o método run

Qual das três formas é a melhor de implementar threads, e em qual situação?

  1. A segunda pergunta é o seguinte, eu optei pela segunda opção(Estender de Thread), e agora eu estou querendo parar a minha Thread, é possível? :?:

Eu poderia mandar ela dormir com o sleep, contudo, o sleep recebe como argumento o tempo em milisegundos, e eu quero que ela durma até segunda ordem, ou seja, até eu mandar ela acordar, :frowning:

Usei o stop, contudo ele é um metodo depreciado (deprecated), então preferi abdicar dessa solução.

Usei o interrupt, e ele lançou uma java.lang.InterruptedException, tentei tratar essa excessão, mas lançou uma illegalMonitorException, tentei tratar a segunda, mas naum capturou-a :shock:

Usei o wait, e ele lançou uma excessão, mas a thread naum parou :x

Me disseram que eu deveria na minha classe, sobrescrever o metodo interrupt para interromper a thread da minha maneira, mas achei que isso era brabeza :roll:

Que que eu faço?

Desculpem pelas duas perguntas, mas quero matar dois coelhos com uma “caixa d’água” só ! :lol:

obrigado,
abraços

já reparou que a própria Classe Thread implementa Runnable?

bem, o melhor seria você implementar Runnable, ao invés de dar extends em Thread… pQ?
Você pode querer dar extends em alguma outra coisa qualquer que quiser.

Sobre como parar as Threads, sabe inglês?
deveria ler esse link da sun, que explica o porque desses métodos se tornarem deprecated, e o que usar no lugar deles!

Sempre prefira implementar uma interface, no caso a Runnable, ao invés de estender uma classe (herança). Lembre-se que o java não permite herança múltipla de classes e se você utilizar neste caso, esta sua classe não poderá herdar de mais ninguém.

Quanto ao fato de parar uma thread, o link indicado pela resposta acima é muito bom. De qualquer maneira, para mim não ficou claro o motivo de você precisar parar a sua thread.

Exemplo de uso de thread:

public class Programa implements Runnable {

private int id;

public void run() {
	for (int i = 0; i &lt 10000000; i++) {
		if (i % 1000 == 0 ) {
			System.out.println("Programa " + id + " valor: " + i);
		}
	}
}

// Constructor method
public Programa (int id) {
	this.id = id;
}	

}

public class Teste {

/**
 * @param args
 */
public static void main(String[] args) {
	Programa p1 = new Programa(1);
	Programa p2 = new Programa(2);		
	
	Thread t1 = new Thread(p1);
	Thread t2 = new Thread(p2);
	
	t1.start();
	t2.start();
}

}

Abraços

Ah pessoal, é o seguinte, estou fazendo um trabalho de Sistemas Operacionais onde implemento a questão do produtor e consumidor, tenho um buffer, e o produtor insere numeros aleatorios no buffer e o consumidor lê do buffer, no caso uso duas threads pra fazerem isso.
Isso ta funcionando legal, contudo na interface grafica tem um botao pra iniciar a produção e parar, o que eu gostaria era que quando o usuario quisesse, eu parasse a produção e posteriormente reiniciá-las, olhem o screenshot,
vou dar uma olhada no link,
valeu pessoal

Reinicia-las? ou continuar de onde parou?

você poderia usar wait() e notify() para fazer isso, se o objetivo é continuar da onde a Thread parou.

Isso, continuar de onde parou, mas quando eu uso o wait, uma excessão é lançada e elas naum param, olha só a saida do console

Produtor produziu: 4
Consumidor leu: 4
Produtor produziu: 6
Consumidor leu: 6
Exception in thread "AWT-EventQueue-0" java.lang.IllegalMonitorStateException
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:485)
	at produtorconsumidor.Main.bPauseActionPerformed(Main.java:348)
	at produtorconsumidor.Main.access$1(Main.java:340)
	at produtorconsumidor.Main$2.actionPerformed(Main.java:150)
	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
	at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
	at org.jvnet.substance.utils.RolloverButtonListener.mouseReleased(RolloverButtonListener.java:110)
	at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:272)
	at java.awt.Component.processMouseEvent(Component.java:6038)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3260)
	at java.awt.Component.processEvent(Component.java:5803)
	at java.awt.Container.processEvent(Container.java:2058)
	at java.awt.Component.dispatchEventImpl(Component.java:4410)
	at java.awt.Container.dispatchEventImpl(Container.java:2116)
	at java.awt.Component.dispatchEvent(Component.java:4240)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4322)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3986)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3916)
	at java.awt.Container.dispatchEventImpl(Container.java:2102)
	at java.awt.Window.dispatchEventImpl(Window.java:2429)
	at java.awt.Component.dispatchEvent(Component.java:4240)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
Produtor produziu: 7
Consumidor leu: 7
Produtor produziu: 3
Consumidor leu: 3

Depois do StackTrace da excesão as threads continuam rodando,

quando usar “wait()” você tem que possuir o Lock do Objeto, e pode fazer de duas maneiras:

Criando um bloco sincronizado:

[code]
synchronized (Object) {

  try {
        wait();
  } catch (InterruptedException e) {

  }

}[/code]

ou quando você estiver em um método sincronizado:

[code]public synchronized void doSomething() {
try {
wait();
} catch (InterruptedException e) {

  }

}[/code]

Esqueci de dizer, naum posso usar monitores, bloco synchronized, pq seria muito fácil (De acordo com o meu professor), tive que implementar esse conceito de semáforo, onde o buffer controla quem pode acessar o que:

/**
 * 
 * @author samuel
 *
 */
public class Buffer {

	private int buffer;

	private boolean semaforo = true;
	
	public int getBuffer() {
		while( !semaforo ){
			try {
				Thread.sleep( 50 );
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return buffer;
	}

	public void setBuffer(int buffer) {
		while( !semaforo ){
			try {
				Thread.sleep( 50 );
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		semaforo = false;
		this.buffer = buffer;
		semaforo = true;
	}
}

Dessa forma, ainda tem alguma solução para mim?

Você tem que fazer o sinal esperar? mudar e etc?

Thread.sleep(50);

não é meio pouco 50 milisegundos? sendo que 1000 == 1 segundo

Esse tempo que vc viu não é o tempo de amostragem da produção na tela, o tempo é 1000 milisegundos e na interface grafica o usuario pode aumentar e tudo mais,
esse tempo ae, é o tempo em que a thread vai verificar se o semaforo mudou de estado, tipo se ela naum puder escrever pq a variavel está false, ela espera 50 milisegundos para verificar de novo, pq se o tempo for maior, o buffer pode passar muito tempo vazio, mas o tempo de amostragem é bem maior, vai de 1 a 5 segundos.

O que eu queria era poder usar um “sleep” só que sem argumento de tempo, só que naum existe essa sobrecarga.

Uma péssima solução seria quando o usuário apertar o botao stop, ele parar de mostrar a produção na interface grafica, contudo, tudo continuar ocorrendo em background, é uma péssima solução, mas se eu naum conseguir fazer isso funcionar, vou usá-la.

Então, existe alguma outra forma de eu usar o wait sem estar com blocos sincronizados?

Respondendo a dúvida inicial, acho que o ideal mesmo é extender Runnable.

Isso porque você separa o mecanismo de disparo da Thread, do que deve ser executado na Thread.

Existe, a partir do Java 5, outros métodos de se criar threads, através da classe ExecutorsService. Você mesmo poderia ser tentado a criar um Pool de Threads no futuro, e então, ter extendido uma classe já te traria prejuízos.

Quanto a fazer um botão de pausa. Não tem outro jeito senão com wait.

Coloque em seus produtores e consumidores um atributo pausado. Enquanto este atributo valer true, você deve parar num while do tipo:

synchronized (this) {
   while (pausado) {
       wait();
    }
}

Depois, dê um notifyAll no método setPausado:

public synchronized void setPausado(boolean pausado) {
    this.pausado = pausado;
    if (!pausado) 
        notifyAll();
}

Note que, mesmo fazendo setPausado(true) pode levar um pequano tempo até que seu código chegue no while e efetivamente pause.

No Java 5 há também classes próprias para implementar a lógica do produtor/consumidor, como a classe CompletionService e LinkedBlockingQueue, que tornam a tarefa ainda mais simples do que usando blocos synchronized.

Valeu ViniGodoy, funcionou!

Deh, eu tinha falado que naum podia usar synchronized, mas depois percebi que nau podia usar na questao do produtor e consumidor, eu usando apenas para fazer a animação, valeu cara,

Obrigado pessoal,

eu tenho duas duvidas, vcs devem axar idiota, mais ai vai,
1- qdo se cria Threads elas trabalham simultaneamente ou eu devo estipular quem vai trabalhar e qdo?
tipo assim , posso criar 2 Threads q processem simultaneamente a informação ou devo estipular a ordem de processamento , 2- posso enviar variaveis de uma Thread para outra??
obrigado

Cara, cada thread só começa sua execução quando acionado o método start, tu não tem como estipular qual tem mais prioridade, o que tu pode fazer é chamar o método setPriority herdado do objeto Thread, mas com isso tu vai estar sugerindo para a maquina virtual o seu processamento, mas não é certo que ela vá acatar a esta regra. As threas são controladas totalmente pela maquina virtual;

Quanto a passar uma variavel para a outra, talvez se uma tiver a instancia da outra sim, ou utilizando alguns outros macetes para isso, como fazendo métodos estáticos ou utilizando uma outra classe auxiliar para isso.

Até mais…

uma thread nao conhece a outra quem diz quem vai executar eh um cara chamado agendador quando se falar em threads nao existe GARANTIAS de nada. um exemplo legal: pegue um cd-room e coloque no seu drive qual garantia que vc tem q ele vai parar bloquear o que vc está fazendo para exibir o conteudo do cd? Nada ti garantir isso, agora tem alguns cd’s que se vc tiver fazendo alguma coisa vamos dizer digitando um texto ai vc pode ele… simplesmente ele bloqueia sua tarefa e exibi a tela inicial do cd… entao threads é isso ai… nada é garantido… e nesse caso do cd eh prioridades uma threads com maior prioridade sempre vai ta em execução…Wolf_X.

flw!!

valeu gente , ajudaram pacas :smiley:

po galera , me da uma mao to tentando aprender a usar a thread e desenvolvi um joguinho de xadrez pra jogar online, olha a minha dificuldade
eu tenho 2 threads
1 eh uma conexao socket e os metodos envolvidos
a outra eh um JFrame com seus objetos , acontece o seguinte
eu tenho q usar o repaint() em um objeto da JFrame toda vez q eu receber uma certa msg da outra thread , ja fiz a comunicação entre elas e ta funcionando (eu axo hahahahahha) acontece q eu nao posso deixar a thread do JFrame parada ateh receber a msg da thread socket pois implementei um drag&drop nela e qdo eu peço um delay ou um wait o D&D para de funcionar , como eu resolvo isso???
alguem tem alguma ideia , ou to indo pelo caminho errado e eh melhor reestruturar isso?