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:
- Is using a dedicated threadpool to update a complex Swing app a sound strategy?
- Is the skeleton code with threadpool thread-safe? Can I update a component inside done(); method? As shown is skeleton code above?
- 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).
CodePudding user response:
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.
CodePudding user response:
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.