Does the current worker participate in work stealing? - java

In a ForkJoinPool ForkJoinTask, does the current worker thread participate in work stealing?
I have read implications that a fork join pool can work steal from blocked or waiting threads. The current worker seems an obvious candidate. Once the worker calls .join() on another task, then that task is essentially blocked.
On the other hand, I see many articles that imply different conclusions. For example, the general consensus that the current worker thread should do work before waiting for forked tasks.
There are a few articles that discuss the use of ForkJoinTask.getSurplusQueuedTaskCount as a method of balancing the work in the queue by having the current worker do some of the work. If the current worker is also stealing, then this doesn't seem necessary.
Naturally, I would like to maximize thread operations and keep all workers running maximally. Understanding if the current thread also steals work (for example when .join is called) will help to clarify.

It is the responsibility of the ForkJoinPool to manage threads. Client code should feed it tasks, not micromanage the threading. Note that tasks and threads are two different things; tasks are units of work to be executed, and threads execute that work.
ForkJoinTask.compute() should fork() into smaller subtasks if the task is large enough to benefit from running parts of the task in parallel, and simply process the task if the task is small enough that it would better be run in a single thread. If the work turns out to be more than expected, it can fork() some of the work and do the rest of it.
If ForkJoinTask.compute() forks into smaller subtasks, it can call join() before returning. The ForkJoinPool will then either free the thread to work on other tasks, or spawn a temporary thread to work on other tasks to ensure the available parallelism is fully utilized.
I think it's reasonable to assume that the appropriate number of worker threads are kept busy for as long as there are uncompleted tasks, unless you explicitly block the thread in the compute() method.
The Sun tutorial provides more specifics on how to use these classes:
https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html

Related

Not Advisable to use wait(),notify() methods in ExecutorService

I am a beginner in multithreading and came across the following in OCJP7 edition:
Avoid using methods such as Object.wait, Object.notify, and Object
.notifyAll in tasks (Runnable and Callable instances) that are
submitted to an Executor or ExecutorService.
Can someone please explain why is this the case?
With an Executor you do not know how tasks are scheduled on threads. Indeed, it is possible for there to be only a single thread.
In the pathological case you end up in a situation where you Object.wait() on a single threaded executor in a task... and there is nothing being run to notify() because it is a single threaded executor. As a result you have deadlock.
Even with more threads you can still end up in a similar deadlock situation if the relevant tasks happen to be scheduled on the same thread.
In any case, the blocking behaviour of Object.wait() means you are stalling a thread, whereas the whole idea of an executor is to farm out as many jobs as possible to a much more limited number of threads. What this means is that even at best you are reducing the throughput significantly by blocking an entire thread and all the other waiting tasks that were scheduled for it. I.e. you are not just blocking the task that does wait() you are also blocking any task scheduled behind it on the same thread since that task must wait to run until your blocking tasks is finished.

Difference between ForkJoinPool and normal ExecutionService?

I read a great article about the fork-join framework in Java 7, and the idea is that, with ForkJoinPool and ForkJoinTask, the threads in the pool can get the sub tasks from other tasks, so it's able to use less threads to handle more tasks.
Then I tried to use a normal ExecutorService to do the same work, and found I can't tell the difference, since when I submit a new task to the pool, the task will be run on another available thread.
The only difference I can tell is if I use ForkJoinPool, I don't need to pass the pool to the tasks, because I can call task.fork() to make it running on another thread. But with normal ExecutorService, I have to pass the pool to the task, or make it a static, so inside the task, I can call pool.submit(newTask)
Do I miss something?
(You can view the living code from https://github.com/freewind/fork-join-test/tree/master/src)
Although ForkJoinPool implements ExecutorService, it is conceptionally different from 'normal' executors.
You can easily see the difference if your tasks spawn more tasks and wait for them to complete, e.g. by calling
executor.invoke(new Task()); // blocks this thread until new task completes
In a normal executor service, waiting for other tasks to complete will block the current thread. There are two possible outcomes: If your executor service has a fixed number of threads, it might deadlock if the last running thread waits for another task to complete. If your executor dynamically creates new threads on demand, the number of threads might explode and you end up having thousands of threads which might cause starvation.
In opposite, the fork/join framework reuses the thread in the meantime to execute other tasks, so it won't deadlock although the number of threads is fixed:
new MyForkJoinTask().invoke();
So if you have a problem that you can solve recursively, think of using a ForkJoinPool as you can easily implement one level of recursion as ForkJoinTask.
Just check the number of running threads in your examples.

Prevent concurrent execution of related tasks in a thread pool or executor service

I have a queue of Runnables to execute that I would like to process using a thread pool. However, some of the tasks in the queue are related to each other (could be implemented by a common hashcode() on the Runnable) and must not be processed concurrently, so, when taking a task off the queue, I would like to check that no currently executing task is related, and if it is, hold back the new task until the related one has completed, but allow other, unrelated tasks to continue (maintaining high throughput is important)
I could do this by a customised ThreadPoolExecutorService and BlockingQueue that tracks the hashcodes of tasks in progress but this is somewhat complex and unwieldy.
is anyone aware of an elegant solution to the problem?

Is ScheduledThreadPoolExecutor ok for doing multiple tasks at same time?

The docs for ScheduledThreadPoolExecutor says that -
Tasks scheduled for exactly the same execution time are enabled in first-in-first-out (FIFO) order of submission.
Does this mean that the tasks which SHOULD be done at the same time are never done at the same time. Instead they are executed in FIFO order ?
If that is true then which class do I use which is better than Timer and also does not have this FIFO problem ?
The way a ScheduledThreadPoolExecutor works is there is a single "scheduling" or master thread which checks for tasks to execute.
If it finds a task, it delegates it to a "worker" thread from the pool.
If multiple tasks are ready to be executed, they are "kicked off" one at a time, though once "kicked off", subsequent processing is concurrent, per Java's definition.
If you have two tasks that are both scheduled through the executor for the same time, the order in which they complete could vary from run to run and unless you put in specific controls such as locks, waits, etc... to handle this, it's up to java's thread scheduling (how java allots time to threads on a core) to determine how and when what gets processed. Please note that setting up such locks, waits, etc... is a deceptively complex task prone to race conditions leading to unexpected deadlocks, live locks, etc...
It depends on the size of your thread pool. If you schedule 1000 tasks to fire at midnight, and you only have 25 threads, then only 25 can be executed initially, while the rest must wait for available threads. FIFO here refers to the order in which the executor will hand tasks off to the execution threads.
Please note that the docs talk about "enabling" the tasks and that we are talking about a threadpool executor. :-)
That means the tasks will wait until the designated time, then they are treated as if put into a normal ThreadPoolExecutor. If there are enough threads available in the pool all these tasks will be run in parallel.
Only if you have more tasks becoming active than available threads in the pool some tasks will have to wait.

Idle threads left with ScheduledThreadPoolExecutor.schedule

I have a Java application that is structured as:
One thread watching a java.nio.Selector for IO.
A java.util.concurrent.ScheduledThreadPoolExecutor thread pool handling either work to be done immediately — dispatching IO read by the IO thread — or work to be done after a delay, usually errors.
The ScheduledThreadPoolExecutor has an upper bound on the number of threads to create; currently 5000 in the app, but I haven't tuned that number at all.
After running the app for a while, I get thousands and thousands of threads that have this stack trace:
"pool-1-thread-5262" prio=10 tid=0x00007f636c2df800 nid=0x2516 waiting on condition [0x00007f60246a5000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x0000000581c49520> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2025)
at java.util.concurrent.DelayQueue.poll(DelayQueue.java:209)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:611)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:602)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:662)
I assume that the above is being caused by my calls to schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit), which certainly happens often in the app. Is this the expected behavior?
Having all of these threads hanging around doesn't seem to impact the application at all — if a worker thread is needed, it does not appear like these TIMED_WAITING threads prevent tasks from running when submitted through the submit method, but I'm not totally sure of that. Does having thousands of threads hanging around in this parked state impact the app or system performance?
Tasks that are submitted via the schedule method are very simple: they basically just re-schedule the Channel back with the Selector. So, these tasks are not very long-lived, they just need to execute at some point in the future. Normal worker threads will do traditional blocking-IO to perform their work, and are generally more long-lived.
A related question: is it better to do delayed tasks in an explicit, single thread instead of using the schedule method? That is, have a loop like this:
DelayedQueue<SomeTaskClass> tasks = ...;
while (true) {
task<SomeTaskClass> = tasks.take();
threadpool.submit(task);
}
Does DelayQueue use any worker threads to implement its functionality? I was going to just experiment with it today, but advice would be well appreciated.
After running the app for a while, I get thousands and thousands of threads that have this stack trace.
Unless you actually plan on having 5000 threads all operating at once, that is a too high number. If they are blocked on IO then that should be fine. Unless you are starting with a minimum number of threads that is too large, then their existence in your thread dump means that at some point they were all needed to process the tasks submitted to the executor. So at some point you had 5000 tasks being run at once -- blocking or whatever. If you show the actual executor constructor call I can be more specific.
If you have the time, playing with that upper bound might be good to see if it does affect application behavior.
Does having thousands of threads hanging around in this parked state impact the app or system performance?
They will take up more memory which may affect JVM performance but otherwise it should not impact the application unless too many are running at once. They may just be wasting some system resources which is the only reason why I'd play with the 5000 and other executor constructor args.
is it better to do delayed tasks in an explicit, single thread instead of using the schedule method?
I'd say no. Just about anytime you can replace by-hand thread code with a use of the ExecutorService classes it is a good thing. I think the idea of doing a task and then delaying for a while is a great use of the ScheduledThreadPoolExecutor.
Does DelayQueue use any worker threads to implement its functionality?
No. It is just a BlockingQueue implementation that helps with delaying of tasks. I've never used the class actually, although I would have if I'd known about it. The ScheduledThreadPoolExecutor uses this class to do its job so using DelayQueue yourself is again a waste. Just stick with STPE.

Categories