0

What is the best way to keep buttons and others components in Swing responsive. I always use "new Thread(){public void run(){}}.start();" on every action listener but I don't know how to stop or cancel the thread without using "Thread.stop()" any suggestions or tips?

  • What should I use then? –  Jul 22 '15 at 12:54
  • Why do you need to stop the threads? when they run() method ends, it will be dead automatically. If you want the children Threads to be stopped and do not wait the main thread from terminating use the setDaemon(true). I can not understand what is your question here. – STaefi Jul 22 '15 at 12:56
  • 1
    You basically do not want to start a Thread for a short task. You are better off using a [ThreadPool](https://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html) Google around examples of those. I can't write an example as question will be closed before I finish. – weston Jul 22 '15 at 12:57
  • 1
    Java is a fine option, but you aren't really asking how to make it responsive. You're asking how to cancel a thread once it has started. That is a valid technical question, but not the way you've worded it. You might want to edit your question to include an example [MCVE](http://stackoverflow.com/help/mcve) along with what you've tried, otherwise this question will be closed in 3... 2... 1... – Kevin Workman Jul 22 '15 at 13:00
  • 1
    Also look at examples of the [`SwingWorker`](https://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html) – weston Jul 22 '15 at 13:00
  • 1
    `I always use "new Thread(){public void run(){}}.start();" on every action listener` - this is unnecessary for every ActionListener. It is only done for potentially long running tasks that will freeze the EDT and therefore make the GUI unresponsive. For example when you access a database or do network I/O or any task that blocks like using Sockets. – camickr Jul 22 '15 at 14:00

2 Answers2

1

My rule of thumb is only start a Thread if it's a very long running task. And by very long running I mean practically the same as the life of the application. Therefore I almost never start my own threads.

Starting a thread for each little operation is a bad idea because Threads are expensive to spin up. The usual solution is to use a ThreadPool which reuse threads and take that headache away from you.

But as it's swing, there is also the option of a SwingWorker which will run on a background pooled thread and give you easy way to update your UI with any results in the correct thread.

From https://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html

final JLabel label;
class MeaningOfLifeFinder extends SwingWorker<String, Object> {
    @Override
   public String doInBackground() {
       return findTheMeaningOfLife();
   }

    @Override
   protected void done() {
       try {
           label.setText(get());
       } catch (Exception ignore) {
       }
   }
}

SwingWorker<String, Object> worker = new MeaningOfLifeFinder();
worker.execute();

Cancelling

See https://docs.oracle.com/javase/tutorial/uiswing/concurrency/cancel.html

Cancelling a swing worker is easy. worker.cancel(false); sets a flag which you must look for by checking isCancelled().

@Override
public String doInBackground() {
   //somework
   if(isCancelled()) return ...; // check occasionally and return early when cancelled
   //somemorework 
   return ...;
}
weston
  • 54,145
  • 21
  • 145
  • 203
  • I don't think the OP is asking how to update the UI from another thread. I think they're asking how to cancel a thread once it's been started. – Kevin Workman Jul 22 '15 at 13:05
  • @KevinWorkman They are asking for the best way to do work in background because they are having problems with the incorrect approach they have so far. – weston Jul 22 '15 at 13:09
  • @KevinWorkman Ok, I see they want to cancel, so I have added that too. – weston Jul 22 '15 at 13:13
0

One quick approach is to simply periodically check whether a thread should continue working or not. Something like this:

public void run(){

   doThingOne();

   if(cancelled){
      return;
   }

   doThingTwo();

   if(cancelled){
      return;
   }

   doThingThree();
}

Then you'd simply set that cancelled variable whenever you want to cancel the thread- from a button labeled "Cancel", for example.

Google is your friend, but see these related questions for more info:

How to stop, pause, cancel a thread in java

Java long running task Thread interrupt vs cancel flag

How do you kill a thread in Java?

How to properly stop the Thread in Java?

And the Java tutorials are always a good place to look: https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html

Community
  • 1
  • 1
Kevin Workman
  • 41,537
  • 9
  • 68
  • 107