[concurrency-interest]ThreadPoolExecutorcustomizationproposal/question

Joe Bowbeer jozart at blarg.net
Sat Apr 2 19:19:05 EST 2005


By the way,

I want to point out that there's no need for this code to use a concurrent 
map or a concurrent queue implementation because this executor's state is 
synchronized at execute and scheduleNext.

Any Queue will do, such as a LinkedList.  I'd recommend switching to 
LinkedList to reduce the overhead per context.

  final Queue<Runnable> tasks = new LinkedList<Runnable>();


----- Original Message ----- 
From: "Joe Bowbeer" <jozart at blarg.net>
To: <concurrency-interest at altair.cs.oswego.edu>; "Hernan Otero" 
<hernan.otero at mac.com>
Sent: Saturday, April 02, 2005 2:07 PM
Subject: Re: 
[concurrency-interest]ThreadPoolExecutorcustomizationproposal/question


Hernan Otero writes:

> The number of contexts is unknown before hand
> (and could significantly go up/down at runtime).
> A rough number would be 5,000.

One approach would be to add a map of execution contexts to SerialExecutor.
Note that unused contexts can be removed in the scheduleNext method.

A crude implementation along these lines follows.

ContextExecutor maps context keys to execution contexts, and serializes the
execution of tasks for each context.  An execution context in this case is
the active task and a queue of waiting tasks.  New contexts are created on
demand and removed when they are no longer used.

import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;

class ContextExecutor implements Executor {

    static class Context {
        final Queue<Runnable> tasks =
            new LinkedBlockingQueue<Runnable>();
        final String key;
        Runnable active;
        Context(String key) {
            this.key = key;
        }
    }

    final Map<String, Context> map =
        new HashMap<String, Context>();
    final Executor executor;

    ContextExecutor(Executor executor) {
        this.executor = executor;
    }

    public synchronized void execute(final Runnable r) {
        final Context c = getContext(r);
        c.tasks.offer(new Runnable() {
            public void run() {
                try {
                    r.run();
                } finally {
                    scheduleNext(c);
                }
            }
        });
        if (c.active == null) {
            scheduleNext(c);
        }
    }

    protected synchronized void scheduleNext(Context c) {
        if ((c.active = c.tasks.poll()) != null) {
            executor.execute(c.active);
        } else {
            map.remove(c.key);
        }
    }

    private Context getContext(Runnable r) {
        String key = r.toString(); // FIXME
        Context context = map.get(key);
        if (context == null) {
            context = new Context(key);
            map.put(key, context);
        }
        return context;
    }
}



----- Original Message ----- 
From: "Hernan Otero" <hernan.otero at mac.com>
To: "Joe Bowbeer" <jozart at blarg.net>
Cc: <hernan.otero at jpmchase.com>; <concurrency-interest at altair.cs.oswego.edu>
Sent: Saturday, April 02, 2005 9:08 AM
Subject: Re: [concurrency-interest]
ThreadPoolExecutorcustomizationproposal/question


The number of contexts is unknown before hand (and could significantly
go up/down at runtime).  A rough number would be 5,000.

Will look into your proposed alternatives.

Thanks,

Hernan

On Apr 2, 2005, at 4:23 AM, Joe Bowbeer wrote:

> Hernan,
>
> How many contexts are there?  Are they known before hand?
>
> I suggest you look at SerialExecutor in the Executor javadoc (if you
> haven't
> already).  The idea being that you can use an instance of
> SerialExecutor per
> context, all of them sharing a single ThreadPoolExecutor.
>
> If SerialExecutor isn't a good fit, I suggest you try a different
> composite
> executor design, or create a specialized queue, leaving
> ThreadPoolExecutor
> to do its thread pool thing unencumbered.
>
>
> ----- Original Message -----
> From: <hernan.otero at jpmchase.com>
> To: <concurrency-interest at altair.cs.oswego.edu>
> Sent: Friday, April 01, 2005 2:55 PM
> Subject: [concurrency-interest] ThreadPoolExecutor
> customizationproposal/question
>
>
> I would like to use a ThreadPoolExecutor but would like to impose a
> couple
> of restrictions on how tasks (Runnables) are executed.  Basically, I
> would
> like to have each task execute on a specific "context" (each context
> having
> a unique String-typed id).  I would like my executor to guarantee
> serialization of the tasks at the context level (e.g. no two tasks for
> the
> same context should ever be executed in parallel).  So if two tasks are
> queued in order (e.g. by the same thread), then their execution should
> also
> be guaranteed to execute in the same order.
>
> If I were to implement this as a customization to the existing
> ThreadPoolExecutor, I would probably think of going the following
> route:
>
> interface RunnableContext
> {
>
> }
>
> interface ContextRunnable extends Runnable
> {
>
> RunnableContext getContext();
>
> }
>
> public class ThreadPoolContextExecutor extends ThreadPoolExecutor {
>
> Runnable getTask() {
>   // the code that looks for the next task would need to skip tasks for
> "currently busy" contexts
> }
>
> public void execute(Runnable task)
> {
>     // we want an exception if task is not a ContextRunnable
>     ContextRunnable contextTask = (ContextRunnable) task;
>     ...
> }
>
> protected void beforeExecute(Thread t, Runnable r) {
>     ContextRunnable contextTask = (ContextRunnable) r;
>     // assert that contextTask.getContext() context's not currently
> marked
> as busy
>     // somehow mark the fact that contextTask.getContext() is now busy
> }
>
> protected void afterExecute(Thread t, Runnable r) {
>     ContextRunnable contextTask = (ContextRunnable) r;
>     // assert that contextTask.getContext() context's currently marked
> as
> busy
>     // mark contextTask.getContext() as no longer busy
> }
>
> }
>
> Would the above be the recommended way to implement such
> functionality?  Or
> are there other hooks I missed which would make this easier to
> implement?
>
> Also, I'm thinking this may not be a very rare need and was wondering
> if
> there has been any thought given to something like this in the past.
> It
> might be worth considering it as a potential future enhancement to the
> library.
>
> Thanks in advance,
>
> Hernan
>

_______________________________________________
Concurrency-interest mailing list
Concurrency-interest at altair.cs.oswego.edu
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest



More information about the Concurrency-interest mailing list