Drawbacks to an idling fixed threadpool - java

I'm currently in the process of doing various performance improvements in a software. As it is using SWT for it's GUI, I have come across a problem where under certain circumstances a lot of UI elements are created in the Display Thread.
Since the person before me, didn't really take care to do any calculations outside of the Display Thread, the whole software can be unresponsive for several seconds on startup.
I've now isolated the code that needs to be performed in the Display Thread, and I'm now calculating everything else in Runnables that I submit to a fixed Threadpool.
I'm using the pool like this:
public abstract class AbstractChartComposite {
private static ExecutorService pool = Executors.newFixedThreadPool(8);
private List<String> currentlyProcessingChartItems = new ArrayList<>();
protected void doCalculate(constraints){
for (IMERuntimeConstraint c : constraints) {
if(!currentlyProcessingChartItems.contains(c.getId())){
currentlyProcessingChartItems.add(c.getId());
pool.submit(new Runnable(){
#Override
public void run() {
try{
createChartItem(c);
currentlyProcessingChartItems.remove(c.getId());
}catch(Throwable e){
e.printStackTrace();
}
}
});
}
}
}
}
I'm now wondering, if I have any drawbacks to leaving the Threadpool running at idle, once all the UI elements have been created. I cannot really shut it down for garbage collection, because it will be needed again on user Input when a new element needs to be created.
So are there any major drawbacks on leaving a threadpool with no submitted Runnables running?

No, there are no drawbacks.
The threads won't be actually running, they'll be parked until a new task is submitted. So it does not affect CPU. Also you say that you will use this pool again, so in your case there's no point of shutting it down and recreating again.
As to the memory - yes, idle threads will consume some amount of memory, but that's not an issue as well, until you have hundreds (thousands?) of threads.
Also, a piece of advice. Do not do premature optimizations. That's the root of all evil. Analyze a problem once you have real performance issues, using special utilities for that and detecting bottlenecks.

Related

Java Swing multithreading: Will a dedicated threadpool for UI updates make the app performant?

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).
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.
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.

new Thread(task).start() VS ThreadPoolExecutor.submit(task) in Android

In my Android project I had a lot of places where I need to run some code asynchronously (a web request, call to db etc.). This is not long running tasks (maximum a few seconds).
Until now I was doing this kind of stuff with creating a new thread, passing it a new runnable with the task. But recently I have read an article about threads and concurrency in Java and understood that creating a new Thread for every single task is not a good decision.
So now I have created a ThreadPoolExecutor in my Application class which holds 5 threads.
Here is the code:
public class App extends Application {
private ThreadPoolExecutor mPool;
#Override
public void onCreate() {
super.onCreate();
mPool = (ThreadPoolExecutor)Executors.newFixedThreadPool(5);
}
}
And also I have a method to submit Runnable tasks to the executor:
public void submitRunnableTask(Runnable task){
if(!mPool.isShutdown() && mPool.getActiveCount() != mPool.getMaximumPoolSize()){
mPool.submit(task);
} else {
new Thread(task).start();
}
}
So when I want to run an asynchronous task in my code I get the instance of App and call the submitRunnableTask method passing the runnable to it. As you can see, I also check, if the thread pool has free threads to execute my task, if not, I create a new Thread (I don't think that this will happen, but in any case... I don't want my task to wait in a queue and slow down the app).
In the onTerminate callback method of Application I shutdown the pool.
So my question is the following: Is this kind of pattern better then creating new Threads in code? What pros and cons my new approach has? Can it cause problems that I am not aware off yet? Can you advice me something better than this to manage my asynchronous tasks?
P.S. I have some experience in Android and Java, but I am far from being a concurrency guru ) So may be there are aspects that I don't understand well in this kind of questions. Any advice will be appreciated.
This answer assumes your tasks are short
Is this kind of pattern better then creating new Threads in code?
It's better, but it's still far from ideal. You are still creating threads for short tasks. Instead you just need to create a different type of thread pool - for example by Executors.newScheduledThreadPool(int corePoolSize).
What's the difference in behaviour?
A FixedThreadPool will always have a set of threads to use and if all threads are busy, a new task will be put into a queue.
A (default) ScheduledThreadPool, as created by the Executors class, has a minimum thread pool that it keeps, even when idle. If all threads are busy when a new task comes in, it creates a new thread for it, and disposes of the thread 60 seconds after it is done, unless it's needed again.
The second one can allow you to not create new threads by yourself. This behaviour can be achieved without the "Scheduled" part, but you will then have to construct the executor yourself. The constructor is
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
The various options allow you to fine-tune the behaviour.
If some tasks are long...
And I mean long. As in most of your application lifetime (Realtime 2-way connection? Server port? Multicast listener?). In that case, putting your Runnable in an executor is detrimental - standard executors are not designed to cope with it, and their performance will deteriorate.
Think about your fixed thread pool - if you have 5 long-running tasks, then any new task will spawn a new thread, completely destroying any possible gains of the pool. If you use a more flexible executor - some threads will be shared, but not always.
The rule of thumb is
If it's a short task - use an executor.
If it's a long task - make sure your executor can handle it (i.e. it either doesn't have a max pool size, or enough max threads to deal with 1 more thread being gone for a while)
If it's a parallel process that needs to always run alongside your main thread - use another Thread.
To answer your question — Yes, using Executor is better than creating new threads because:
Executor provides a selection of different thread pools. It allows re-use of already existing threads which increases performance as thread creation is an expensive operation.
In case a thread dies, Executor can replace it with a new thread without affecting the application.
Changes to multi-threading policies are much easier, as only the Executor implementation needs to be changed.
Based on the comment of Ordous I have modified my code to work with only one pool.
public class App extends Application {
private ThreadPoolExecutor mPool;
#Override
public void onCreate() {
super.onCreate();
mPool = new ThreadPoolExecutor(5, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new SynchronousQueue<Runnable>());
}
}
public void submitRunnableTask(Runnable task){
if(!mPool.isShutdown() && mPool.getActiveCount() != mPool.getMaximumPoolSize()){
mPool.submit(task);
} else {
new Thread(task).start(); // Actually this should never happen, just in case...
}
}
So, I hope this can be useful to someone else, and if more experienced people have some comments on my approach, I will very appreciate their comments.

ConditionVariable prevents both threads from running simultaneously

I am trying to enforce synchronization between a pair of Android threads for game programming purposes. I have assigned a game thread, which handles most duties, and a render thread, which is tasked with swapping buffers and rendering. When I first asked about thread synchronization, I was referred to the ConditionVariable object as a useful tool to force threads to block until concurrent tasks are completed.
My source code looks like this:
...
final ConditionVariable bufferLock = new ConditionVariable();
final ConditionVariable cycleLock = new ConditionVariable();
bufferLock.open();
cycleLock.open();
Runnable bufferSwapTask = new Runnable()
{
public void run()
{
swapBuffers();
bufferLock.open();
}
};
Runnable renderTask = new Runnable()
{
public void run()
{
Log.d(TAG, "drawAll");
drawAll();
cycleLock.open();
}
};
while(!halt)
{
if(!init)
{
synchronized (userInputLock)
{
fetchUserInput();
}
processUserInput();
gameLogic();
bufferLock.block();
cycleLock.close();
renderThreadHandler.post(renderTask);
recycleDisplayObjects();
enqueueDisplayTree();
cycleLock.block();
bufferLock.close();
renderThreadHandler.post(bufferSwapTask);
}
}
...
So things executed in the right order, but not with the level of performance I had expected. And, when I activated DDMS method tracing, I found that the DVM would actually interrupt and block each thread to allow the other thread to resume, switching back and forth in a manner that strongly suggests that both threads are only being processed by one CPU.
I have had nice simultaneous processing results using ReentrantLocks, so why does ConditionVariable have this effect?
The Linux kernel on Android tries to avoid moving threads between cores. If a thread is "runnable" (i.e. could run but is waiting on another thread) for a while, the kernel can decide to migrate it to another core.
If, in the previous implementation, one of your threads tended to run continuously, it may have kept the other thread in "runnable" long enough to cause the kernel to migrate it. The new implementation might be moving in smaller steps and fall below the threshold.
FWIW, other people have been puzzled by this, e.g. here and here.

How to terminate container-created threads in Java

I am running a multi-threaded Java web application on Apache Tomcat 6. Instead of using the new Thread(); anti-pattern, I leave thread instantiation to Tomcat (see code below).
I noticed in the last days that the web application gets slower and slower. After restarting the servlet container everything is back to normal.
Since I am not terminating threads after processing them (Don't know if I have to or if the Garbage Collector will destroy them), I am guessing that this is the cause for the performance loss.
The code basically looks like this:
Custom Server Listener (I added this to web.xml):
public class MyTaskRunner implements ServletContextListener {
public static final ExecutorService EXECUTOR_SERVICE = ExecutorService.newFixedThreadPool(10000);
public void contextDestroyed(ServletContextEvent sce) {
EXECUTOR_SERVICE.shutdownNow();
}
public void contextInitialized(ServletContextEvent sce) {
}
}
Thread instantiation:
for (Object foo : bar){
MyTaskRunner.EXECUTOR_SERVICE.submit(new Runnable() {
public void run() {
doSomethingWith(foo);
});
}
So, is there anything special that I have to do after run() has finished?
Some basic facts about threads and GC:
While a thread is running, it will not be garbage collected.
When a thread is terminated, its stack is deleted and its Thread object is removed from the ThreadGroup data structures. The remainder of the threads' state is subject to the normal reachability rules.
You don't need to do anything special to make a thread terminate. It happens when the run method call ends, either because it returned, or because it exited with an (uncaught) exception.
Now to your particular problem. Many things could be causing your performance degradation. For instance:
Some of your threads may be getting stuck; e.g. waiting on a lock, waiting for a notify that isn't going to arrive, or just stuck in an infinite CPU loop.
You may have too many threads running (doing useful, or semi-useful things), and the slowdown may be a result of lock contention, CPU resource starvation, or thrashing.
You may have a memory leak of some kind, and the slowdown may be a symptom of your application starting to run out of heap space.
To figure out what is going on, you are going to need to do some performance monitoring:
Look at the OS level stats to see if the application is thrashing.
Use a memory profile to see if your application is short of memory. If it is, see if there is a memory leak, and track it down.
Use a performance profiler to see if there are particular hotspots, or if there is a lot of lock contention.
I agree with the comment. A thread pool size of 10000 is dangerously large. It should be a small constant multiplied by the number of cores available to your application.
Are you registering the context listener in web.xml correctly?
Does your run methods end at some point? or do they keep running indefinitely?
The ExecutorSerfice will simply call Thread.start for you, you are still starting threads from inside your webapp, which is not inherently such a terrible thing as long as you shut them down properly. No matter what tecnique you use, the execution of your run() method will not be truncated.
new Thread(); anti-pattern
where do you people get that this is an anti-pattern?
anyway, 10000 threads is way too much. Each thread takes up memory and OS has its own limitations, so, as a safe path, try not to exceed a couple thousand threads.
connect jconsole (jstack might be enough) to see what your threads are doing - whether they're just sleeping, or waiting for something.
and it's not Tomcat who's managing the threads, it's ExecutorService inside java.

Having threads run from event listeners in java?

I have a program that creates hundreds of instances of a class, each of which listens to another thread which simply fires an event on a regular timed schedule (so that they all perform at the same speed). What I'd like is for each of the hundreds of instances to be its own thread, so that when an event is fired, they can all work in parallel. What makes sense to me is to have these classes extend the Thread class and then have this code inside them...
public class IteratorStepListener implements StepEventListener {
public void actionPerformed(ActionEvent e) {
start();
}
}
public void run() {
doStuff();
}
This doesn't seem to work though. Clearly I'm not understanding something basic here. What's the proper way to do this?
Okay, first thing: overcome the notion that your hundreds of threads will run in parallel. At the very best, they will run concurrently, ie, time-sliced. As you get into the hundreds of threads, you will see the bearings on the scheduling algorithm start to glow; in the thousands they'll smoke and eventually seize up, and you'll get no more threads.
Now, that said, we don't have near enough code to understand what you're really doing, but one thing that I note is you don't seem to be making new Threads. Remember that a thread is an object; the canonical way to start a thread is
Thread t = new Thread(Runnable r);
t.run();
What it looks like is that you're trying to run() the same thread over and over again; this way lies madness. Have a look at Wiki on Event Driven Programming. If you really want to have a separate thread for handling each event, you'll want a scheme something like this (pseudocode):
processEvents: function
eventQueue: queue of Events
event: implements Runnable
-- something produces events and puts them on the queue
loop -- forever
do
Event ev := eventQueue.front
new Thread(ev).run();
od
end -- processEvents
It sounds like the event is going to be fired more than once... but you can't start the same thread more than once.
It sounds like your listener should implement the interface but start a thread directly in actionPerformed (or better, use an Executor so that it could use a thread pool). So instead of your current implementation, you could use:
// Assuming the listener implements runnable; you may want to
// delegate that to a separate class for separation of concerns.
public void actionPerformed(ActionEvent e) {
new Thread(this).start();
}
or
public void actionPerformed(ActionEvent e) {
executor.execute(this);
}
What I'd like is for each of the hundreds of instances to be its own thread, so that when an event is fired, they can all work in parallel.
I don't think this is a good approach.
Unless you have hundreds of processors, the threads cannot possibly all work in parallel. You'll end up with the threads running them one at a time (one per processor), or time-slicing between processors.
Each thread actually ties down a significant slice of the JVM's resources, even when inactive. IIRC, the default stack size is about 1 Mbyte.
The example code in your question shows the event calling start() on the thread. Unfortunately, you can only call start() on a thread once. Once the thread has terminated it cannot be restarted.
A better approach would be to create an executor with a bounded thread pool, and have each event cause a new task to be submitted to the executor. Something like this:
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize,
keepAliveTime, timeUnit, workQueue);
...
public class IteratorStepListener implements StepEventListener, Runnable {
public void actionPerformed(ActionEvent e) {
executor.submit(this);
}
public void run() {
doStuff();
}
}
You can't use threads like that in Java. This is because Java threads directly map to underlying OS threads (at least on JVM implementations that I'm aware of), and OS threads can't scale like that. A rule of thumb is, you want to keep total number of threads within hundred or something in an app. A few hundred is probably ok. A few thousand gets usually problematic, depending on the HW you are using.
The use of threads like you described is a valid implementation strategy in languages like Erlang for example. Meanwhile, if you are stuck with Java this time, creating a shared thread pool and submitting your tasks to this instead of allowing all tasks to run concurrently might be a good alternative. In this case, you can choose a suitable number of threads (best number depends on the nature of the task. If you have no idea, number of CPU core available times 2 is a good start), and have that number of tasks run concurrently.
If you absolutely need all tasks to proceed concurrently, it could get a little complicated, but that's doable as well.

Categories

Resources