This week's giveaway is in the Android forum.
We're giving away four copies of Android Security Essentials Live Lessons and have Godfrey Nolan on-line!
See this thread for details.
The moose likes Threads and Synchronization and the fly likes ExecutorService invokeAll - blocking? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Java » Threads and Synchronization
Bookmark "ExecutorService invokeAll - blocking?" Watch "ExecutorService invokeAll - blocking?" New topic
Author

ExecutorService invokeAll - blocking?

Tom McAmmond
Ranch Hand

Joined: Feb 16, 2004
Posts: 58
I have a question about the Concurrent library introduced in Java 5. If I have a Collection of threads and I want to launch them in a separate thread (so my main application isn't blocked waiting for them all the finish) can I create a new SingleThreadExecutor and use invokeAll(threadList) ?

Does invokeAll() block my current thread, or is an Executor automatically running in its own thread? I know I can use Submit(task), which I don't *think* blocks my current thread, but I want to use the timeout feature that I can get from invokeAll().

Thanks to any concurrency gurus!
[ December 21, 2006: Message edited by: Tom McAmmond ]
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18543
    
  40

Does invokeAll() block my current thread, or is an Executor automatically running in its own thread? I know I can use Submit(task), which I don't *think* blocks my current thread, but I want to use the timeout feature that I can get from invokeAll().


invokeAll() does indeed run the callable tasks in it's own thread, but it also blocks waiting for the tasks to complete. submit() does not block.

On one hand, not waiting for completion *and* using a timeout, doesn't make sense. After all, a timeout is the maximum amount of time that you are willing to wait. On the other hand, I see the point. You want to have a timeout for cancellation, not for waiting for completion.

I don't think that there is a direct way to do this -- you will need two executors. Create the first executor, and submit() a "new" task. This "new" task will create a second executor, and invokeAll() on the collection of tasks. The main thread will not wait as it submit the task to the first executor, and this first executor will wait on the tasks, and cancel upon timeout.

Henry


Books: Java Threads, 3rd Edition, Jini in a Nutshell, and Java Gems (contributor)
Tom McAmmond
Ranch Hand

Joined: Feb 16, 2004
Posts: 58
Thank you for the reply - that's exactly right, of course, I want to kill my threads if they take too long to finish, because something must have gone wrong. I also want to run them in sequence (for various reasons involving exclusive access to an object in the Main thread via accessors while they're running), not in parallel, hence the SingleThreadExecutor.

So from the sounds of it, I want to create a customized SingleThreadExecutor that has a list of Threads but launches a second SingleThreadExecutor with invokeAll on my blocking list, with a timeout....

Time to go and buy some books on Concurrency, I'm thinking, before I get a headache I appreciate the insight you've given me.

- Tom
Tom McAmmond
Ranch Hand

Joined: Feb 16, 2004
Posts: 58
Originally posted by Henry Wong:


submit() does not block.



I understand that if I create a new Executor with:


my new Executor is launched in its own thread, correct? So it just sits there idling, and I can then feed it tasks once in a while with submit() and those tasks will run sequentially. But is the "workerService" running as a Daemon thread so it won't prevent my application from shutting down? If not, can I turn it into one?

Thanks,

Tom
[ December 20, 2006: Message edited by: Tom McAmmond ]
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18543
    
  40

Originally posted by Tom McAmmond:

my new Executor is launched in its own thread, correct? So it just sits there idling, and I can then feed it tasks once in a while with submit() and those tasks will run sequentially. But is the "workerService" running as a Daemon thread so it won't prevent my application from shutting down? If not, can I turn it into one?

Thanks,
Tom


Hmmmm... I never thought to ask that question. I always thought, since the Javadoc doesn't mention it, that standard rules apply -- meaning if the executor was created by a user thread, then it has user threads. And if the executor was created by a daemon thread, then it has daemon threads. Since the main thread is a user thread, the executor should have user threads.

Now... you can also "turn it into one" -- in the case where you want the executor to have a different type than it's creator. Just call the version of the method that takes a ThreadFactory. In this thread factory, you just need to create a thread and configure it the way you want to.

Henry
Tom McAmmond
Ranch Hand

Joined: Feb 16, 2004
Posts: 58
Originally posted by Henry Wong:
Now... you can also "turn it into one" -- in the case where you want the executor to have a different type than it's creator. Just call the version of the method that takes a ThreadFactory. In this thread factory, you just need to create a thread and configure it the way you want to.


I'm confused I understood that the ThreadFactory would create threads in which to run the tasks that I submit() to the Executor, but the ThreadFactory would have no bearing on the type of thread that my Executor actually ran in. Is my understanding of Executors fundamentally flawed?

When I create my new SingleThreadExecutor am I not creating a thread that launches other Runnables by creating a new Thread with the given ThreadFactory (or the default ThreadFactory) and passing in my Runnable?

Does an Executor not, then, consist of a thread itself?

Hope you can shed some light on this one...

Thanks,

Tom
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18543
    
  40

What you need to do is create a thread factory for the executor. Normally, the executor will call an internal factory which simply does a "new Thread(runnable)" for the executor to use. What you need to do is create a new factory that does a "new Thread(runnable)" followed by a "setDaemon(true)". The factory doesn't start the thread, it merely creates it.

You then call the newSingleThreadExecutor() method, passing it your new factory. When the executor creates it's internal threads, it will use your factory which will create daemon threads.

Here is an example that does what you want...



Henry
[ December 20, 2006: Message edited by: Henry Wong ]
Tom McAmmond
Ranch Hand

Joined: Feb 16, 2004
Posts: 58
Thank you for the example - yes, what you say makes perfect sense. I'm not explaining the question very well, I think. Let me rephrase:

In this case, is the workerService simply an object that launches threads with a thread factory? OR is it a reference to a Thread that launches threads with a thread factory? The fact that it has Shutdown() methods suggests that it is a running thread - a service that can be shutdown.... doesn't it?

So if it is a user thread, then I cannot shutdown my application because the workerService is still running, regardless of the type of threads that it spawns. On the other hand, if it's simply a Service... then my understanding is deeply flawed.

- Tom
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18543
    
  40

Not sure what you are asking... But an executor is *not* a thread object. It manages thread objects -- which it uses to execute the runnables and callables tasks.

Henry
Tom McAmmond
Ranch Hand

Joined: Feb 16, 2004
Posts: 58
Ah... ok, that clears things up immensely. I can't imagine why I wasn't certain of that.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Well, both Executor and ExecutorService are abstractions which typically hide one or more Thread objects behind the scenes. But the specifications are intentionally vague on these details, because they don't want to limit the implementation options unnecessarily. For example it would be perfectly legal (if somewhat pointless) for an ExecutorService to use no additional threads, and do everything in the current thread, blocking whenever necessary. Or it could use one additional thread, or a finite thread pool, or simply create a new thread for each task with no other bounds. The docs don't spell out exactly what happens, precisely because they want to leave options open for different implementations. Unfortunately that can make it a bit more difficult for us to read the docs and understand the intent.


"I'm not back." - Bill Harding, Twister
Tom McAmmond
Ranch Hand

Joined: Feb 16, 2004
Posts: 58
That's also good information...

I've figured out why I was confused, and it's because the SingleThreadExecutorService (created from the static factory) does not work as I thought it should work - it almost seems like the implementation of ThreadPoolExecutor is broken....

Originally, I thought I would have a Service to which I would submit Runnable objects, and when it received one it would launch my Runnable in a new Thread. But I noticed that even when my Thread's task finished, there was still a thread running that was stopping my application from shutting down.

What IS happening is this:

The SingleThreadExecutor simply creates a ThreadPoolExecutor with a CorePoolSize equal to 1, and a MaxPoolSize equal to 1, and when you pass it a Runnable it gets a thread out of the pool to run your task. When a ThreadPoolExecutor is finished running a task it tries to bring the number of active threads back down to the CorePoolSize.

So I thought - no problem - I'll just start one with a CorePoolSize of zero instead, so that when my task is finished it will kill the active thread and my application can shut down properly later on. BUT - here's the problem:

ThreadPoolExecutor.execute(Runnable) includes the following code:

if (poolSize < corePoolSize && addIfUnderCorePoolSize(command))
return;

So now my corePoolSize == 0 and my poolSize == 0 it will never add a new thread to process my task, and nothing will happen other than my task queue will increase by one more value.

Personally I think this is very odd behaviour, and the javadocs for that class (and that method) indicate that it should be otherwise.... don't you think?
[ December 21, 2006: Message edited by: Tom McAmmond ]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
It looks like this was a bug in JDK 5 that's been fixed in JDK 6. I didn't find a clear bug report, but testing both 5 and 6 seems to show it works in 6. Looking at the source code for 5, I think the problem is actually a little after that part you quoted:

The poolSize < corePoolSize will never be true, so that if statement is skipped, and that's OK... because there's supposed to be another opportunity later with the addIfUnderMaximumPoolSize(). Which makes sense, as we are under maximum pool size. Except that we never quite get there if workQueue.offer() returns true, because then we return. Now the command has been accepted into the queue, but no threads have been created to process the queue. Oops.

If you can't switch to JDK 6, one (rather odd) workaround is to use a queue that will reject the offer, at least the first time it's used. That way execution will proceed down to addIfUnderMaximumPoolSize(command), and a thread will get started in the ThreadPoolExecutor.
Tom McAmmond
Ranch Hand

Joined: Feb 16, 2004
Posts: 58
Thank you so much for (indirectly) re-affirming my sanity, and for the explanation I was staring at the screen a little too long to catch where the problem really was, I guess.

Sadly, I cannot switch to Java6 yet, but my understanding of the concurrency libraries has increased exponentially thanks in part to you and Henry, and this bug that I had to research!
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[Tom]: Thank you so much for (indirectly) re-affirming my sanity

Hey now, I wouldn't go that far!
Tom McAmmond
Ranch Hand

Joined: Feb 16, 2004
Posts: 58
Just read through the Java6 code of ThreadPoolExecutor. It looks like they rewrote large portions of it, and yes, they definitely addressed this bug. Shame they haven't backported the fix to Java5.
 
 
subject: ExecutorService invokeAll - blocking?
 
Similar Threads
MSCS or MSIT
Count all threads
doubt on Thread join() and yield() method
Please help Newbie
Multiple Threading