Passing thread priorities to thread pools
I have a Java component that does some super complicated business logic, some of it parallelized and threads executing subtasks are pooled. Now each request to this component can have some priority thats is mapped in some way to thread priority. A the the beginning of execution i can assign a proper priority to executing thread. The problematic part is to pass priority to each threads executing subtasks. I know that spawning a new child thread will accomplish this because child threads inherit priority of parent threads but i would like to take advantage of thread pooling. An the question:
- Is there a way to ensure that each thread in execution path has proper priority ?
- How can i monitor threads priority at each stage of execution, of course i don't want to hard-code any tracing code? On thing that came into my mind is to write some tracing script in BTrace
You want to use thread pools, which would be made useless if you had to spawn new threads just to set job priority.
I think you want each job (not thread) to have a different priority. If that is the case, let's look at a constructor signature for ThreadPoolExecutor:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
- Instead of using one of the recommended Executors' factory methods to construct your thread pool, do new ThreadPoolExecutor(...) yourself, using one of its numerous signatures.
- Pass Executors.defaultThreadFactory into this constructor (the signature I listed above does this internally). This will do automatic thread priority assignment as it creates the threads (for a fixed size thread pool, that should happen just once per thread, at app start).
- Pass a BlockingQueue<Runnable> or PriorityBlockingQueue<Runnable> into this constructor. This is the queue which will allow you to prioritise jobs (not threads).
- Extend Runnable into an abstract PriorityRunnable class which allows get/set of priority. These represent the jobs, so when you want to make a new job, simply extend this and custom-set the priority as appropriate for that job.
- Implement Comparator to perform ordering on elements as you insert them into the queue, and let that queue use it.
- Add your jobs to the queue.
Note that if you have your queue already populated by this time (eg. for batch processing apps), you can call executor.prestartAllCoreThreads() or executor.prestartCoreThread(n) at once after construction.
It's all pretty simple, and takes surprisingly few lines of code to set up.
EDIT: Just found the same approach being discussed over at Java Ranch.
I assume you already know this, but whether JDK Thread's priority value matters or not is highly OS-specific, and may translate to "has no effect whatsoever". So are you sure it actually matters? If so, maybe edit question to mention OS that system runs on.
Also: it is not very common to even try to use thread priorities; in addition to priorities not necessarily working, it is not trivial to make good use of them even if they work. More commonly synchronization primitives are used, as well as controlling level of concurrency (number of active threads), not priorities. This because there are seldom benefits to have having more active CPU-bounds Threads than cores system has.
As far as setting the priority of the thread is concerned, you can use the different methods of the Executors class which take a ThreadFactory. This factory would be responsible for the creation of threads based on the passed in "Runnable".
Regarding monitoring, can you extrapolate on the scenario you are trying to address here when you say "each stage of execution"? As it has been mentioned elsewhere, since there isn't a clear mapping between Java and OS thread priorities, relying on these priorities would be a bad thing, in case that is what you are attempting here.
I recently implemented this. I did it much as Nick Wiggill suggested.
But you can't just do what he suggested, because ThreadPoolExecutor doesn't put the jobs you asked for in the workQueue--instead, it wraps them in its own RunnableFuture and puts them in the queue. So you have to override its newTaskFor method to pass along the priority.
The source code is online under the Apache 2.0 license: https://github.com/TheClimateCorporation/claypoole/blob/master/src/java/com/climate/claypoole/impl/PriorityThreadpoolImpl.java
This could solve your problem: Thread.currentThread().setPriority([1..5]);
You can use them from anywhere. If you use them from inside a runnable launched by a thread pool, you can control the single thread priority and change it as needed.