Ayuda con los hilos

necesito saber como terminar con un hilo.
por que al ejecutar mi código con un botón, la segunda vez no funciona aun que en teoria ya haya acabado su función

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

SwingWorker

 

Primeramente, te recomiendo ejecutar tu tarea utilizando una instancia de javax.swing.SwingWorker (desde Java 6). En segundo lugar, si quieres saber más sobre cómo crear y ejecutar hilos en Java Swing, échale un vistazo a Concurrency in Swing. Por último, si pudieras agregar más detalles de tu requerimiento o programa (un poco de código no estaría mal), sería de gran ayuda.

~~~

Imagen de Nopalin

un hilo comienza así: new

un hilo comienza así:

new Thread(runnable).start();

la implementación de la interface Runnable es necesaria para hacersela al objeto thread. la JVM entonces inicia un nuevo thread cuando llamas al metodo start() y ese asu vez ejecuta el metodo run de la interface Runnable. Cuando la llamada al método run termina, entonces tu thread termina.

Imagen de Rafael Carrillo

si tienes razon

pero mi metodo start inicia con un botón y al tratar de ejecutarlo por segunda vez falla aun que el hilo haya acabado su función

Imagen de Cid

Quieres hacer alguna tarea en segundo plano ?

Si requieres hacer una tarea en segundo plano lo más recomendable como ya te mencionaron es utilizar SwingWorker (metodo doInBackgound), en el curso que a continuación coloco enseñan un ejemplo básico muy entendible y de SwingWorker, tambien tiene un metodo que te indica cuando termino de realizar su tarea el hilo (done).

Java Multithreading

Imagen de julgo

start solo una ves

el método start solo debe ser llamado una ves , esta en especificación del método , si no quieres usar swing worker instancia un nuevo Thread .

Imagen de Cid

Es correcto

Lo que menciona @julgo es importante creo que todos pensabamos que por cada botón iniciabas un nuevo hilo o algo asi:

public void actionPerformed(ActionEvent e){

   Thread t = new Thread(new TuRunnable());
   t.start();

}

Pero si lo que tienes es algo como lo que muestro en el siguiente código, te causará una excepción (IllegalThreadStateException)

Thread t = new Thread(new TuRunnable());

public void actionPerformed(ActionEvent e){

   t.start(); //Provocarias que se invoque start() más de una vez sobre la misma referencia al hilo.

}

Imagen de Rafael Carrillo

a ok

entonces mi error es mandar llamar más de una vez al start en vez de llamar al run..disculpen por tanta pregunta pero apenas voy en preparatoria y estoy estudiando esto de los hilos por cuenta propia

Imagen de Cid

Pero entonces porque con hilos ?

Si solo llamas a run podrias hacer lo mismo con cualquier otro método, si llamas a run no estas invocando ningún hilo nuevo.

Imagen de Rafael Carrillo

por que se me hizo interesante y hasta cierto punto dificil

muchas gracias por la ayuda

Imagen de Cid

Para aprender más

Libro:

Java Concurrency

Tutorial
Multithreading and Concurrency in Java

Y el videotutorial que coloque anteriormente aborda temas básicos entendibles, aunque si no conoces algunas cosas como clases anónimas e interfaces primero hechale una leída a esos temas.

Imagen de ezamudio

Hilo

No, el error es invocar start() en la misma instancia de Thread cada vez. Cada hilo sólo puede ser iniciado una vez. Por eso es recomendable NO extender Thread, sino tener un Runnable y pasarlo a un Thread; así puedes ejecutar el método run() del mismo objeto varias veces incluso de manera concurrente (obvio sólo es recomendable si tu Runnable no guarda estado).

Lo que menciona SrCid seguramente es tu solución: invocar new Thread(runnable).start() dentro del actionPerformed; es decir, crear un nuevo hilo con tu runnable cada vez que opriman el botón. Ojo, obvio esto implica que si alguien aprieta el botón varias veces seguidas, vas a echar varios hilos a andar, ejecutando todos la misma tarea. Si necesitas que sea solamente una vez, entonces necesitas monitorear el estado del hilo:

Thread t = null;
Runnable r = /*creas tu Runnable */

void actionPerformed(ActionEvent ev) {
  if (t == null || !t.isAlive()) {
    t = new Thread(r).start();
  } else {
    //Presenta un JOptionPane con un mensaje de que la tarea sigue en ejecución
  }
}

Imagen de Rafael Carrillo

gracias a todos

este foro me es muy útil

Imagen de Rafael Carrillo

solucionado al final mi codigo quedo asi les debo una

  Thread azar=null;
Runnable runAzar;

runAzar= new Runnable(){
        public void run(){
            try{
               
              GenerarAzar Azar = new GenerarAzar();
        int dado;
        dado = Azar.getDado();

        if (dado == 1) {
            ImageIcon Imagen1 = new ImageIcon(getClass().getResource("/imagenes/Uno.png"));
            lblDado.setIcon(Imagen1);
            Thread.sleep(1500);
            lblDado.setIcon(null);
       
        }
        if (dado == 2) {
            ImageIcon Imagen2 = new ImageIcon(getClass().getResource("/imagenes/Dos.png"));
            lblDado.setIcon(Imagen2);
        Thread.sleep(1500);
        lblDado.setIcon(null);
        }
        if (dado == 3) {
            ImageIcon Imagen3 = new ImageIcon(getClass().getResource("/imagenes/Tres.png"));
            lblDado.setIcon(Imagen3);
        Thread.sleep(1500);
        lblDado.setIcon(null);
        }
        if (dado == 4) {
            ImageIcon Imagen4 = new ImageIcon(getClass().getResource("/imagenes/Cuatro.png"));
            lblDado.setIcon(Imagen4);
            Thread.sleep(1500);
            lblDado.setIcon(null);
       
        }
        if (dado == 5) {
            ImageIcon Imagen5 = new ImageIcon(getClass().getResource("/imagenes/Cinco.png"));
            lblDado.setIcon(Imagen5);
            Thread.sleep(1500);
          lblDado.setIcon(null);
       
        }
        if (dado == 6) {
            ImageIcon Imagen6 = new ImageIcon(getClass().getResource("/imagenes/Seis.png"));
            lblDado.setIcon(Imagen6);
            Thread.sleep(1500);
          lblDado.setIcon(null);
       
        }    
       
            }
            catch(Exception ex){
                JOptionPane.showMessageDialog(null,ex.getMessage());
            }}};
private void btnLanzarMonedaActionPerformed(java.awt.event.ActionEvent evt) {  
  if (azar== null || !azar.isAlive()) {
    t = new Thread(runAzar).start();
  } else {
 JOptionPane.showMessageDialog(null,"Espere por favor");
  }
}

Imagen de julgo

ese código no es escalable

ese código no es escalable por lo menos mas de la mitad de las líneas son innecesarias, que tal si en ves de seis imágenes tengas que trabajar con 10 , 20 o mas , una mejora es que tengas una sola variable ImageIcon y le pases un String con el valor del numero al azar :

//aquí tu variable..( yo la llamare numeroAzar)  puede contener uno, dos ,tres ,...etc
  getResource("/imagenes/"+numeroAzar+".png")
 

¿Qué tal si ... es el mismo recurso?

 

Con esta mejora, sólo habría menos código ... porque en cada ejecución se seguiría creando una instancia de javax.swing.ImageIcon, sin importar que se trate del mismo recurso.

¿No sería mejor tener un mapa?:

private Map<Integer, ImageIcon> map = new HashMap<>();

Y para la creación de cada javax.swing.ImageIcon, ésta podría ser en modo eager (todos a la vez) o en modo lazy (conforme se vayan necesitando), cuidando siempre de crear uno por cada recurso.

~~~

Imagen de Rafael Carrillo

Entiendo el comentario de julgo

pero esto me da pena pero no conozco los mapas y la verdad no se que son , si me pudieran decir mas o menos que son sería genial.y gracias por las recomendaciones las voy a aplicar.

Imagen de Rafael Carrillo

con lo que entendí el codigo se redujo en esto

 public void run(){
            try{
               
              GenerarAzar Azar = new GenerarAzar();
        int dado;
        dado = Azar.getDado();

       
            ImageIcon Imagen1 = new ImageIcon(getClass().getResource("/imagenes/"+dado+".png"));
            lblDado.setIcon(Imagen1);
            Thread.sleep(1000);
            lblDado.setIcon(null);    
            }
            catch(Exception ex){
                JOptionPane.showMessageDialog(null,ex.getMessage());
            }}};

y al final el botón

Re: mapas

 

Hola, Rafael. He aquí un ejemplo* completo:

package com.company.app;

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.WindowConstants;

public class DiceFrame extends JFrame {

    private Map<Integer, ImageIcon> map;
    private Random random;
    private JLabel label;
    private JButton button;

    public DiceFrame() {
        super("Dice");
        map = new HashMap<>();
        random = new Random();
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        setLayout(new FlowLayout());
        label = new JLabel();
        label.setPreferredSize(new Dimension(150, 150));
        add(label);
        button = new JButton("Throw of the dice");
        button.setPreferredSize(new Dimension(150, 30));
        button.addActionListener(evt -> play());
        add(button);
        pack();
        setLocationRelativeTo(null);
        loadIcons();
    }

    private void loadIcons() {
        for (int i = 1; i <= 6; i++) {
            map.put(i, new ImageIcon(getClass().getResource("/images/dice/" + i + ".gif")));
        }
    }

    public void play() {
        Timer timer1 = new Timer(0, evt1 -> {
            button.setText("Wait...");
            button.setEnabled(false);
            Icon icon = map.get(random.nextInt(map.size()) + 1);
            label.setIcon(icon);
            Timer timer2 = new Timer(1500, evt2 -> {
                label.setIcon(null);
                button.setText("Throw of the dice");
                button.setEnabled(true);
            });
            timer2.setRepeats(false);
            timer2.start();
        });
        timer1.setRepeats(false);
        timer1.start();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new DiceFrame().setVisible(true));
    }

}

Dice

────────────────
* Las imágenes para este ejemplo fueron obtenidas de http://www.speedymath.com/images/dice/1.gif al http://www.speedymath.com/images/dice/6.gif.

~~~

Imagen de Rafael Carrillo

Hola, gracias por la ayuda

se ve que todavía me falta mucho por aprender pero hay voy de poco en poco.

lo que le entendí a ese código es que el mapa lo usan para almacenar el total de rutas de imagenes y un int que sirve como un Id para la ruta guardada y le asignan con el Random la ruta al Label.