'How do you name a SwingWorker thread? Open to code or best practices

I'm trying to debug a horrible exception that is occurring in a SwingWorker thread. If I could name my SwingWorker threads, then I could better interpret the stack traces I am receiving.

It doesn't seem possible to name a SwingWorker thread (is it?). I'm looking for any best practices or 'tricks' to help me properly identify my worker threads, short of just peppering my code w/ log statements.



Solution 1:[1]

While you don't have access to the ThreadFactory that SwingWorker is using, you can call Thread.currentThread().setName() in your run() or call() method of whatever class the SwingWorker is running.

Just be sure that you're setting that value when the thread is actually executing the code

Solution 2:[2]

The Thread used by SwingWorker is from an Executors.defaultThreadFactory which means it's from a pool. So, naming the thread could be misleading if "MyXYZThread" gets reused for another SwingWorker in the system that fails to rename the thread.

I'd extend the SwingWorker to include a name and log that name when throwing an exception.

Note: I'd rather not make the caller responsible for handling the exception, but I don't see a way to do it without altering the contract of SwingWorker.

private static abstract class MySwingWorker<X, Y> extends SwingWorker<X, Y>
{
    private final String taskName;
    public MySwingWorker(String name)
    {
        this.taskName = name;
    }
    public String getTaskName() {
        return taskName;
    }
}

Usage:

new MySwingWorker<Object,Object>("my task") {
    protected Object doInBackground() {
        try {
            return someCall();
        }
        catch(Exception e) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, 
                "Exception in " + getTaskName(), e);
            throw e;
        }
    }
}.execute();

Solution 3:[3]

You should be able to use reflection to get the thread and call setName as well. You would need to make use of the setAccessible method to do that and some digging around to find the names of the variables you need to access.

I would not prefer this method, but it may be just as "hacky" as any other way...

Solution 4:[4]

The best practice would be to use the already mentioned Thread.currentThread().setName(String).

A "trick" would be setting the ThreadFactory for SwingWorkers:

sun.awt.AppContext context = sun.awt.AppContext.getAppContext();

int maxWorkers = 10;
ThreadFactory factory = ...
ExecutorService executor = Executors.newFixedThreadPool(maxWorkers, factory);

context.put(SwingWorker.class, executor);

This uses a class from the sun.awt package, so you've been warned.

Solution 5:[5]

import javax.swing.SwingWorker;

public class SwingWorkerName {

    public static void main(String[] args) throws Exception {
        new SwingWorker() {
            @Override
            protected Object doInBackground() throws Exception {
                final String previousThreadName = Thread.currentThread().getName();
                Thread.currentThread().setName("My Worker Thread");
                try {

                    // DO YOUR WORK HERE
                    Thread.sleep(100000L);

                    return null; // or return whatever you want
                } finally {
                    Thread.currentThread().setName(previousThreadName);
                }
            }
        }.execute();        
        Thread.sleep(100000L);
    }

}

NOTE: In NetBeans, the new name of the swingworker thread did not appear in the debugger until I paused the application or hit a breakpoint.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kevin
Solution 2 Devon_C_Miller
Solution 3 TofuBeer
Solution 4 Robert J Saulnier
Solution 5 Jonathan