Theme Template

OK, so I have a Java GUI application that allows the user to select and run between 5-500 software devices, each represented by a stream. Threads keep updating the GUI with information.

The user can select threads and pause, resume or kill them.

All information about threads and thread pools, interrupts, Future .... I just got lost and wanted to set the internet on fire =)

I need some clear guidance on a standard way to do this. I have below plan for my thread class.

Is this a good template to start with? If not, edit.

package ACsimForm;

import java.util.Random;
import javax.swing.SwingUtilities;

public class Squeak implements Runnable {

    private  String name = "";  
    private  javax.swing.JTextArea ScroolPage;


        Squeak (String name, javax.swing.JTextArea MW )
        {
            this.value = true;
            this.name = name;
            this.ScroolPage = MW;
        }


         Random r = new Random();
         int num = r.nextInt(10-1) + 1;


    @Override
   public void run ()
        {                                 
            updateGUI("Thread "+name+" Loaded and Running");

            while(true)
            {
                updateGUI("New Data");

                try {                        
                      TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    updateGUI("Thread "+name+" Exiting!");
                    //return exits the method killing the thread
                    return;
                }                
            }                               
        }



 //this is the new way to communicate back to the GUI 
 private void updateGUI(final String foo) {
 SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
          ScroolPage.append(foo+"\r\n");      
        }
      });
    }
    }

      

What's the best way to keep 500 threads maximum in such a way that you can kill or pause / resume them from the GUI?

Many thanks.

+1


source to share


2 answers


I think yours is Runnable

almost missing. Ditch the magic flag idea Boolean

- it suffers from problems (read volatile

). Use interrupt as a signal. That's why he's there!

Here's a simple example of a system with an arbitrary number Thread

s:

private static final class Printer implements Runnable {

    private final String printMe;

    public Printer(String printMe) {
        this.printMe = printMe;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + "says: " + printMe);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException ex) {
                return;
            }
        }
    }
}

public static void main(String[] args) throws Exception {
    final ExecutorService executorService = Executors.newCachedThreadPool();
    final Map<Integer, Future<?>> futures = new HashMap<>();
    for (int i = 0; i < 10; ++i) {
        futures.put(i, executorService.submit(new Printer("Printer" + i)));
    }
    final Scanner scanner = new Scanner(System.in);
    while (true) {
        final String input = scanner.nextLine();
        if ("EXIT".equalsIgnoreCase(input)) {
            break;
        }
        final Integer threadToStop;
        try {
            threadToStop = Integer.parseInt(input);
        } catch (NumberFormatException ex) {
            System.out.println("Not a number");
            continue;
        }
        final Future<?> f = futures.remove(threadToStop);
        if (f == null) {
            System.out.println("Not a valid thread");
            continue;
        }
        f.cancel(true);
    }
    executorService.shutdownNow();
}

      

We use ExecutorService

to control Thread

- you should never use Thread

directly, this is plagued by land mines again.

An ExecutorService

arbitrary number of tasks is specified in the request - you can see how to add tasks to the loop for

.



Then ExecutorService

returns Future

for each added task - these are the task descriptors. They allow us to check if they continue to run or were running or if errors were found.

We are Map

Future

for task names and allow the user to selectively kill tasks from input.

You cannot "pause" and "resume" a Thread

(well, you can, but you better not worry about that). You just cancel the task when you want to pause it, and then re-issue it to restart it. It's good that it will ExecutorService

rework what Thread

the task was started on, so you won't lose performance.

If you issue commands Map

from Future

multiple threads, you will need ConcurrentHashMap

.

A common mistake is that your application will automatically shutdown and launch ExecutorService

. This is not the case. ExecutorService

spawns non-daemon threads and therefore the application cannot exit until everything is done. You have two options; the first one is a bit hacky - just give ExecutorService

your own ThreadFactory

and create a daemon Thread

, the second one is to shutdown ExecutorService

when you're done with it, as I have in the example.

+1


source


This is not a complete answer, but a few tips to get things done.

You should use ExecutorService

for your streams and .submit()

theirs. To register them and have them available, say by name, create Map<String, Future<?>>

.



Some pseudo-codes could be improved:

@GuardedBy("this") // see JSR 305
final Map<String, Future<?>> allSqueaks
    = new HashMap<String, Future<?>>();
final ExecutorService service
    = Executors.newCachedThreadPool();

// Registering:
public synchronized void registerSqueak(final Squeak squeak)
{
    allSqueaks.put(squeak.getName(), service.submit(squeak));
}

// Cancelling:
public synchronized void cancelSqueakByName(final String name)
{
    // Note: deal with non existing name if it can happen
    final Future<?> victim = allSqueaks.remove(name);
    victim.cancel(true);
}

      

0


source







All Articles