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
- Inicie sesión o regístrese para enviar comentarios
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
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.~~~
un hilo comienza así: new
un hilo comienza así:
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.
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
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
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 .
Es correcto
Lo que menciona @julgo es importante creo que todos pensabamos que por cada botón iniciabas un nuevo hilo o algo asi:
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)
public void actionPerformed(ActionEvent e){
t.start(); //Provocarias que se invoque start() más de una vez sobre la misma referencia al hilo.
}
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
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.
por que se me hizo interesante y hasta cierto punto dificil
muchas gracias por la ayuda
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.
Hilo
No, el error es invocar
start()
en la misma instancia deThread
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étodorun()
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: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
}
}
gracias a todos
este foro me es muy útil
solucionado al final mi codigo quedo asi les debo una
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");
}
}
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 :
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?:
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.~~~
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.
con lo que entendí el codigo se redujo en esto
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:
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));
}
}
────────────────
* Las imágenes para este ejemplo fueron obtenidas de
http://www.speedymath.com/images/dice/1.gif
alhttp://www.speedymath.com/images/dice/6.gif
.~~~
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.