Dudas sobre hilos

Iniciado por m@o_614, 12 Febrero 2015, 04:53 AM

0 Miembros y 1 Visitante están viendo este tema.

m@o_614

Saludos tengo el siguiente código que trata sobre construir una aplicación basada en hilos que contemple la ejecución de un hilo evento y su interacción con un hilo Thread.

Para realizar la aplicación tengo que cumplir con los siguientes requerimientos:

1. Ambos hilos impriman un contador en áreas de texto particulares.
2. Un hilo imprima cada segundo y el otro cada 2 segundos.
3. Incluir un botón para asociarlo en tiempo compilación a uno cualquiera de los hilos.
4. Al presionar el botón, que el hilo correspondiente suspenda su ejecución.
5. El hilo reanude su ejecución tras otro botonazo con el mismo botón que el punto anterior.
6. La suspensión del hilo conlleve a suspender los efectos del hilo
sobre su correspondiente área de texto.
7. El evento del botonazo, provoque el paso de solo un mensaje al objeto hilo, indicándole
   solo que ha ocurrido un botonazo, por lo que el método a invocar no deberá recibir
parámetro.

y el codigo es el siguiente:

Código (java) [Seleccionar]
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class Hilo extends Thread{
private int cuenta;
private long segundos;
private boolean imprime;

Hilo(int seg,int contador){
cuenta = contador;
segundos = seg;
imprime = true;
}

public void run()
{
while(imprime)
{
System.out.println(""+cuenta);
cuenta++;
}
}
}

class Interfaz extends JFrame implements ActionListener{
private JTextArea areaTexto1,areaTexto2;
private JButton boton;
private JPanel ventana;
private Hilo hilo1,hilo2;

Interfaz()
{
areaTexto1 = new JTextArea(10,10);
areaTexto2 = new JTextArea(10,10);
boton = new JButton("Ejecutar");
ventana = new JPanel(new BorderLayout());
ventana.add("South",areaTexto1);
ventana.add("North",areaTexto2);
hilo1 = new Hilo(1000,0);
hilo2 = new Hilo(2000,0);
        this.add(ventana);
       
boton.addActionListener(this);
}

public void actionPerformed(ActionEvent evento)
{
      hilo1.start();
      //hilo1.sleep(seg);
}
}


public class MensajesHilos {

public static void main(String[] args) {
Interfaz interfaz = new Interfaz();
interfaz.setTitle("Manejo de Hilos");
interfaz.setBounds(200, 200, 400, 400);
interfaz.setVisible(true);
}
}


El problema que tengo es que en el método run() que es el que ejecuta el hilo, no se como hacerle para asignarle un area de texto para que imprima en ella, porque el area de texto la tengo declarada en la clase de interfaz, y en el actionPerformed de la clase interfaz, que es la que me dice que acción ejecutar con el evento botonazo, pero no tengo muy claro para hacer que en el primer botonazo pare el hilo, que al segundo reanude la ejecución y asi sucesivamente

de antemano gracias

3n31ch

#1
Con hilo evento te refieres a un event dispatch thread? si es así porque creas dos hilos?

Por cierto nunca añadiste el botón.

Te intentaría ayudar, pero si te soy sincero no te entiendo nada, le diré a Gus a ver si el entiende que es lo que quieres  :P

Edito:

Ok, el tampoco te entendió.

Te recomiendo que modifiques tu mensaje y solo pongas tu duda o dudas (enumeradas) de esta manera te podremos responder, ya que con el mensaje actual no me queda claro que es lo que quieres xD!

Usuario Invitado

Para serte sincero no te entendí un carajo xD. Releyendo el enunciado entendí algo.

Usa el patrón MVC para poder interactuar entre modelo/vista/controlador.

Vista:
Código (java) [Seleccionar]
public class GUI extends JFrame {

private Controller ctrl;

public GUI() {
this.ctrl = this;
buildGUI();
}

private void buildGUI() {
JButton btnOne = new JButton("btnOne");
JButton btnTwo = new JButton("btnTwo");

btnOne.addActionListener(ctrl);
btnTwo.addActionListener(ctrl);
...
}
}


Controlador:
Código (=java) [Seleccionar]
public class Controller implements ActionListener {

private GUI gui;
private Timer timer;
private int clicCount = 0;

public Controller(GUI gui) {
this.gui = gui;
timer = new Timer();
}

public Controller
@Override public void actionPerformed(ActionEvent evt) {
if(evt.getActionCommand().equals("btnOne")) {
clicCount++;
if(clicCount == 2) {
timer.cancel();
return;
}
timer.schedule(new ThreadBuilder("btnOne", "Mensaje 1", gui), 0, 1000);
}
else if (evt.getActionCommand().equals("btnTwo")) {
clicCount++;
if(clicCount == 2) {
timer.cancel();
return;
}
timer.schedule(new ThreadBuilder("btnTwo", "Mensaje 2", gui), 0, 2000);
}
}
}


Una tarea controlada por tiempo: (Modelo)
Código (=java) [Seleccionar]
public class ThreadBuilder implements TimerTask {

private String actionCommand;
private String message;
private GUI gui;

public ThreadBuilder(String actionCommand, String message GUI gui) {
this.actionCommand = actionCommand;
this.message = message;
this.gui = gui;
}

@Override public void run() {
if(actionCommand.equals("btnOne")) {
gui.getTextAreaOne().setText(message);
} else {
gui.getTextAreaTwo().setText(message);
}
}
}



El método schedule recibe un objeto tipo TimerTask, el timeout que es el tiempo de espera el cual una vez expirado se ejecutará por primera vez el thread y el intérvalo de ejecución en milisegundos.

Solo eso te pude entender. Espero te sirva de algo.
"La vida es muy peligrosa. No por las personas que hacen el mal, si no por las que se sientan a ver lo que pasa." Albert Einstein

m@o_614

muchas gracias por sus respuestas, creo que no me explique muy bien porque de hecho yo tampoco entendía completamente las especificaciones para el código.

Espero poderme explicar mejor esta vez. Yo tengo una interfaz gráfica en la que tengo 2 areas de texto y un boton. En cada area de texto me va a imprimir el contador de un hilo(como son dos areas de texto son 2 hilos). El contador de ambos inicia desde 0. Uno de  los hilos va impriendo el contador cada segundo y el otro cada 2 segundos.

Después voy a elegir uno de los hilos(el que sea), y ese hilo lo voy a asociar con el boton de la interfaz. Cuando yo oprima el boton va a ocurrir un evento boton, en el cual se tiene que parar la ejecución de ese hilo solamente, (el otro seguira imprimiendo como si nada), esto con el uso de una bandera. Y es ahi donde esta el problema que tengo porque para un hilo la bandera va a tener valor true siempre, pero en el otro hilo cuando tenga un botonazo la bandera va a ser false, indicando que pare

Código (java) [Seleccionar]
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


class Hilo extends Thread{
private int cuenta = 0;
private long pausa;
private boolean puedeImprimir = true;
private JTextArea areaTexto;

Hilo(long milisegundos,JTextArea cuadroTexto){
pausa = milisegundos;
   areaTexto = cuadroTexto;
}

public void run()
{
while(puedeImprimir)
{
try
{
imprimirContador();
sleep(pausa);
cuenta++;
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}

public void imprimirContador() {
String tiempo;
   tiempo = Integer.toString(cuenta);
   areaTexto.setText(tiempo);
}
}

class Interfaz extends JFrame implements ActionListener{
private JTextArea areaTexto,areaTexto2;
private JButton boton;
private Hilo hilo,hiloEvento;

Interfaz()
{
areaTexto = new JTextArea(10,7);
areaTexto2 = new JTextArea(10,7);
hilo = new Hilo(2000,areaTexto);
hiloEvento = new Hilo(1000,areaTexto2);
boton = new JButton("Ejecutar");
this.getContentPane().add(boton,BorderLayout.SOUTH);
this.getContentPane().add(areaTexto,BorderLayout.WEST);
this.getContentPane().add(areaTexto2,BorderLayout.EAST);

       hilo.start();
       hiloEvento.start();
       
boton.addActionListener(this);
}

public void actionPerformed(ActionEvent event)
{
    ????????????????????
}
}

public class MensajesHilos {

public static void main(String[] args){
Interfaz interfaz = new Interfaz();
interfaz.setTitle("Hilos de Control");
interfaz.setBounds(200, 200, 300, 240);
interfaz.setVisible(true);
}
}


lo que quiero es tener una variable booleana en la que su valor en un hilo sea siempre true,y en el otro se haga false cuando haya un botonazo

3n31ch

 :xD :xD :xD :xD
La vez pasada creí que querías parar el event dispatch thread o algo asi  :xD

No entiendo que es lo que te complica.

Por que no haces en la clase Hilo un:

Código (java) [Seleccionar]
public void setPuedeImprimir(boolean puedeImprimir){
       this.puedeImprimir = puedeImprimir;
}


Después de todo solo quieres detenerlo no? (no quiere reanimarlo)

y luego en la interfaz haces:

Código (java) [Seleccionar]
public void actionPerformed(ActionEvent event) {
       hiloEvento.setPuedeImprimir(false);
}


o no funciona?

m@o_614

muchas gracias Nac-ho, funciona perfectamente. No se por qué se me complicó algo tan simple. Una última duda si después de que de el primer botonazo(con la respectiva suspensión) yo quiero reanudar la impresión con otro botonazo, ¿cuál sería la mejor opción???


3n31ch

#6
Si no te quieres complicar, al segundo botonazo reasigna asl hiloEvento un nuevo Thread con las mismas características y dale start otra vez (código basura, pero funcionara)

En el thread agrega un get:

Código (java) [Seleccionar]
public boolean getPuedeImprimir(){
      return puedeImprimir;
}


Y este seria tu action performed:


Código (java) [Seleccionar]
public void actionPerformed(ActionEvent event) {

      if(hiloEvento.getPuedeImprimir()){
               hiloEvento.setPuedeImprimir(false);
       } else {
               hiloEvento = new Hilo(1000,areaTexto2);
               hiloEvento.start();
      }
}


:xD :xD :xD (esto se me ocurre para que no tengas que ocupar ningún conocimiento extra al que ya tienes).




Modifico. Me arrepentí por darte una respuesta tan fea   :xD te dejare una un poco mejor:

puedes detener el hilo sin modificar tu boolean. haciendo lo siguiente:

Código (java) [Seleccionar]
hiloEvento.wait(); // Para pausar

hiloEvento.notify(); // Para reanudar


El tema es que hiloEvento.wait() puede generar un error, asi que tendras que contenerlo en un try catch, igual como lo haces con Thread.sleep();

Entonces te quedaría algo así:

Código (java) [Seleccionar]
try {
            hilo.wait();
        } catch (InterruptedException ex) {
            Logger.getLogger(Hilo.class.getName()).log(Level.SEVERE, null, ex);
        }


Eso para pausar, y para reanudar:

Código (java) [Seleccionar]
hilo.notify();

^^




PD: te recomiendo estudiar mas tu lógica, retrocede un poco y haz ejercicios que no utilicen thread ni nada raro, solo clases y objetos, seguramente en el foro encontraras ejercicios.



PD: Una manera bonita de hacer tu ejercicio es mediante synchronized por si acaso, pero eso que te puse debería ser suficiente (espero, no creo que de error).

Suerte, y pásate por los post de buenas practicas y convenciones en java (eso de utilizar mas de una clase en un archivo...)

m@o_614

Saludos Nac-ho, tienes razon, necesito practicas más. Esta es mi primer practica en la que uso hilos y es por eso que me pierdo. Ya estuve leyendo sobre el metodo wait() y el notify() junto con synchronized. El wait creo que funciona correctamente, pero el notify que es el que me desbloquea el hilo no me reanuda la impresion, qué estoy haciendo mal?

Código (java) [Seleccionar]
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.concurrent.atomic.AtomicBoolean;

class Hilo extends Thread{
private int cuenta = 0;
private long pausa;
private boolean puedeImprimir = true;
private JTextArea areaTexto;

Hilo(long milisegundos,JTextArea cuadroTexto){
pausa = milisegundos;
    areaTexto = cuadroTexto;
}

public void ocurrioBotonazo(){
    if(puedeImprimir)
    {
        this.puedeImprimir = false;
        suspender(this);
    }
    else
    {
    this.puedeImprimir = true;
    reanudar(this);
    }
}



public synchronized void suspender(Hilo hilo)
{
if(hilo.puedeImprimir == false)
{
try
{
hilo.wait();
}
catch(InterruptedException e){
}
}
}

public synchronized void reanudar(Hilo hilo)
{
if(hilo.puedeImprimir)
   hilo.notify();
}

public void run()
{
while(this.puedeImprimir)
{
try
{
this.imprimirContador();
Thread.sleep(pausa);
this.cuenta++;
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}

public void imprimirContador(){
String tiempo;
    tiempo = Integer.toString(cuenta);
    areaTexto.setText(tiempo);
}
}

class Interfaz extends JFrame implements ActionListener{
private JTextArea areaTexto,areaTexto2;
private JButton boton;
private Hilo hilo,hiloEvento;

Interfaz()
{
areaTexto = new JTextArea(10,7);
areaTexto2 = new JTextArea(10,7);
hilo = new Hilo(2000,areaTexto);
hiloEvento = new Hilo(1000,areaTexto2);
boton = new JButton("Pausar/Reanudar");
this.getContentPane().add(boton,BorderLayout.SOUTH);
this.getContentPane().add(areaTexto,BorderLayout.WEST);
this.getContentPane().add(areaTexto2,BorderLayout.EAST);

hilo.start();
        hiloEvento.start();
       
boton.addActionListener(this);
}

public void actionPerformed(ActionEvent event)
{
      hiloEvento.ocurrioBotonazo();
}
}


public class MensajesHilos {

public static void main(String[] args){
Interfaz interfaz = new Interfaz();
interfaz.setTitle("Hilos de Control");
interfaz.setBounds(200, 200, 300, 240);
interfaz.setVisible(true);
}
}


en la función de ocurrioBotonazo, en la parte donde dice que puedeImprimir es verdadero otra vez ( o sea que hubo un 2do botonazo) lo mando a reanudar() y el notify no me lo cacha

3n31ch

#8
Ahora estoy algo apurado, asi que te pondré el código, analizalo:

Este es tu thread:

Código (java) [Seleccionar]
class Hilo extends Thread{
private int cuenta = 0;
private long pausa;
private boolean puedeImprimir = true;
private JTextArea areaTexto;

Hilo(long milisegundos,JTextArea cuadroTexto){
           pausa = milisegundos;
   areaTexto = cuadroTexto;
}
       
       Hilo(long milisegundos,JTextArea cuadroTexto, int cuenta){
           pausa = milisegundos;
   areaTexto = cuadroTexto;
           this.cuenta = cuenta;
}

public void run() {
           while(puedeImprimir) {
               this.imprimirContador();
               this.cuenta++;
               try {
                   Thread.sleep(pausa);
               } catch(InterruptedException e) {
                   e.printStackTrace();
               }
           }
}

public void imprimirContador(){
   areaTexto.setText(cuenta+"");
}

   public boolean isPuedeImprimir() {
       return puedeImprimir;
   }

   public void setPuedeImprimir(boolean puedeImprimir) {
       this.puedeImprimir = puedeImprimir;
   }
       
       
}


Este es tu actionPerformed:

Código (java) [Seleccionar]
public void actionPerformed(ActionEvent event) {
           if(hiloEvento.isPuedeImprimir()){
               hiloEvento.setPuedeImprimir(false);
           } else {
               hiloEvento = new Hilo(1000,areaTexto2,Integer.parseInt(areaTexto2.getText()));
               hiloEvento.start();
           }
}


// El código no es robusto pero funciona.

Y ya en serio, pásate por los post de buenas practicas. Y para de avanzar con Threads y esas cosas. Estudia lo basico.

PD: Se me olvidaba. Agrega el JFrame.EXIT_ON_CLOSE en interfaz.