1

Currently, am using the method below for a basic swing app that I expect will grow in complexity

public void actionPerformed(ActionEvent e)
{
  new Thread(new Runnable()
   {
    //do heavy db stuff--------------------------------------------
    DAO dao = DAO.getInstance();
    List<Employees> employeeList = dao.getAllEmployees();
    EmployeeModel empModel = new EmployeeModel(employeeList);
    SwingUtilities.invokeLater(new Runnable() 
    {
      public void run()
      {
         //update swing GUI----------------------------------------
        jTableEmployees.setModel(empModel);
      }
    });
  }).start();
}

I have read this answer and answer and preparing early for the app will grow in complexity. My strategy to UPDATE THE UI of a large complex swing app is using Executor service as shown below.

import java.awt.event.ActionEvent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.SwingWorker;

public class SwiftExcecutor {

    private final ExecutorService exec = 
Executors.newFixedThreadPool(2);

    private class GetEmployeesThread extends SwingWorker<String, String>{

        @Override
        protected String doInBackground() throws Exception {
            return "complete.";
        }
    
         @Override
        protected void done() {
         //Safely update swing components------------------------------
        }

    }

private class GetContractorsThread extends SwingWorker<String, String>{

    @Override
    protected String doInBackground() throws Exception {
       return "complete.";
    }
    
     @Override
    protected void done() {
     //Safely update swing components------------------------------
    }
}

public void actionPerformed(ActionEvent e) {
    
  
    GetEmployeesThread getAllEmployees = new GetEmployeesThread();
    exec.execute(getAllEmployees);
    
    GetContractorsThread getAllContractors = new GetContractorsThread();
    exec.execute(getAllContractors);
    }    
}

My main concern is:

  1. Is using a dedicated threadpool to update a complex Swing app a sound strategy?
  2. Is the skeleton code with threadpool thread-safe? Can I update a component inside done(); method? As shown is skeleton code above?
  3. Should I expect any performance gains in UI response?(Not in sql queries and long running background task, I understand this is a different issues all together).
Afroid1000
  • 149
  • 10
  • 1
    Thread creation isn't expensive at all compared to getting all the employees from your DAO, so a pool is for the ease of use rather than performance. Don't mistake code clarity for performance optimization. There's more to code than performance, even though beginners are obsessed with performance when they have the least clue how to achieve it. – Kayaman May 27 '22 at 06:37
  • 1
    You are confusing connection pool and thread pool. A connection pool keeps a bunch of database connections in order to avoid having to create new ones. A thread pool keeps a bunch of threads. It is not the same thing. You could use a thread pool for UI updates, but the approach suggested in the link is better. – ewramner May 27 '22 at 06:38
  • 1
    Replaced title, both to remove SHOUTY CAPS and to replace threadpool by thread (becasuse, as @ewrammer comments, you were not using any extra threadpools at all) – tucuxi May 27 '22 at 06:39
  • @Kayaman indeed what you say is enlightening, I thought the pool will improve performance, so its actually code clarity? Ouch. In the code sample, am not using any extra threadpools, yes, but i was wondering if replacing them with a thread pool will improve performance. Which seems not to be the case. – Afroid1000 May 27 '22 at 06:51
  • By the way, in the not so distant future, the new feature of [virtual threads](https://openjdk.java.net/jeps/425) in [*Project Loom*](https://wiki.openjdk.java.net/display/loom/Main) may make threads *very* cheap, using much less memory and CPU. – Basil Bourque May 27 '22 at 06:53
  • @ewramner, I thought a connection pool is a type of threadpool dedicated for db access? An edit in my question will help you straighten me up on this issue.. – Afroid1000 May 27 '22 at 07:00
  • @Afroid1000 both are object pools, but one pools threads and the other pools DB connections. Also, whenever you even think about improving performance, you need to measure it to know how much it was improved. Otherwise you're just blindly doing things, not knowing if you're improving or hurting performance, and basically just acting randomly. – Kayaman May 27 '22 at 07:13
  • @Kayaman updated the question for clarity. Thanks. – Afroid1000 May 27 '22 at 08:28
  • @ewramner updated the question for clarity. Thanks. – Afroid1000 May 27 '22 at 08:29
  • @matt if the purpose of a threadpool is to make thread creation less expensive by reusing them, shouldn't one prefer to use a thread pool? On the other hand, thread creation is not as expensive as I initially thought, but I since the app will be large, I prefer to put all the threads (Swing workers) calling the db in one dedicated pool which will also be updating the UI...does this make sense? – Afroid1000 May 27 '22 at 08:35
  • @matt My UI was slightly slow till I rewrote the code using invoke later as the first code sample above. Is the first piece of code scalable? Creating threads every time an actionPerformed() method is called? Would it be better to create a threadpool where threads are already created and actionperformed will not create a thread but reuse the ones in the pool as the second code sample? – Afroid1000 May 27 '22 at 08:52

2 Answers2

1

Think of this in terms of "extra work". Creating a thread is more expensive than, say, sorting a list of 1000 numbers (a "small" task). It is much less expensive than, say, connecting to a DB and retrieving the results of a query (a "big" task, as in your example). If your application

  • launches a thread whenever it does small stuff, and spends a lot of time doing small stuff... then it spends more time in thread creation than in doing stuff. This is bad for performance.
  • launches a thread whenever it does big stuff, and spends a lot of time doing big stuff... then threads are not part of the problem, and you should optimize the big stuff instead (maybe cache DB results to avoid unnecessary repeat queries, optimize the queries themselves, ...).

There is little performance to be gained by improving something that does not already take a substantial part of running time (because you can never make it take negative time, so your potential gains are small).

To answer your original question: no, you should not worry about thread pools in the current state of your application. The scalability bottleneck will be the queries to the DB (or the input-output, if not backed by a DB), not the threads.

tucuxi
  • 17,561
  • 2
  • 43
  • 74
  • I appreciate your answer, i have re-edited the question to be more clear. Thanks – Afroid1000 May 27 '22 at 08:23
  • The gist of my answer still applies: thread creation & related overheads will have minimal effect on the performance of your application, if the work done in the thread far outweighs the (not that big to begin with) thread management costs. The bottlenecks will lie elsewhere. It is still good practice to do as you propose in your latest answer - but not so much for performance, but because you have a more explicit control over degree of parallelism. – tucuxi May 27 '22 at 09:36
  • Thank you sir, a little knowledge is indeed dangerous...I was overtaken by the statement in some literature that ** thread creation is expensive ** and sort to minimize it, but your explanation puts things in perspective. It should not be an issue normally. – Afroid1000 May 27 '22 at 09:45
0

I think what you've written is sound, it fixes some of the issues creating a new thread vs re-using one.

The basic structure of a swing app is. Your UI generates an event, on the EDT you decide what action that event is and then you process it on your event loop that event loop could be an ExecutorService, it could be a literal while loop, or it could even be just firing of another thread.

When you're finished with the event, you decide on any changes and post those changes to the EDT.

So I would not say that is "A dedicated threadpool for updating the UI".

Your SwingWorker looks fine. They'll execute once on a background thread and they'll respond on the EDT when finished. They are agnostic to the type of executor they're being submitted to.

What is wrong with using new Thread();

  • You can fire off many successive events and generate a lot of threads that are working completely independently.
  • You need to keep track of the threads if you want to access the job somehow. ie interrupt.
  • It provides no control or a way to check if the job has finished.

These are issues that can be addressed by using an ExecutorService. The only issue you don't really address is, if somebody clicks the button twice, you'll get two tasks working completely in parallel. You have at least restricted it to the size of your pool.

matt
  • 10,892
  • 3
  • 22
  • 34