[concurrency-interest] On-demand Construction of Threads inThreadPoolExecutor

David Holmes davidcholmes at aapt.net.au
Tue Jan 17 17:30:48 EST 2012


Because it amortizes the construction cost to create threads lazily. If you
want eager you can request it.

It is still an open RFE (6452337) to prefer to re-use an existing idle
Thread rather than create a new one when under core size.

David
  -----Original Message-----
  From: concurrency-interest-bounces at cs.oswego.edu
[mailto:concurrency-interest-bounces at cs.oswego.edu]On Behalf Of Dr Heinz M.
Kabutz
  Sent: Wednesday, 18 January 2012 2:44 AM
  To: Vitaly Davidovich
  Cc: concurrency-interest
  Subject: Re: [concurrency-interest] On-demand Construction of Threads
inThreadPoolExecutor


  I like Joe's point and it was something I also considered.  This was a
nice trade-off to have a single class that could handle both fixed and
cached thread pools.

  My question, however, was specifically about fixed thread pools and why
they did not just allocate the desired number of threads up front when the
thread pool was constructed.

Regards

Heinz
--
Dr Heinz M. Kabutz (PhD CompSci)
Author of "The Java(tm) Specialists' Newsletter"
Sun Java Champion
IEEE Certified Software Development Professional
http://www.javaspecialists.eu
Tel: +30 69 72 850 460
Skype: kabutz


  On 1/17/12 6:38 PM, Vitaly Davidovich wrote:
    Yes that's right but if that one thread is sufficient you get efficiency
benefits.  I'm not sure if you're saying you still disagree or not though :)

    Joe brings up other good points as well, such as starting threads in
ctor and ability to configure the pool after construction (although most
tweaks can be done after threads are running).

    Sent from my phone

    On Jan 17, 2012 11:00 AM, "Dr Heinz M. Kabutz"
<heinz at javaspecialists.eu> wrote:

      Ah, but the Cached Thread Pool always has a core size of zero.  By
default the threads expire after a minute of not being used.

      import java.util.concurrent.*;

      public class CachedThreadPoolTest {
        public static void main(String[] args) throws ExecutionException,
InterruptedException {
          ThreadPoolExecutor pool = (ThreadPoolExecutor)
Executors.newCachedThreadPool();

          System.out.println("initial pool size: " + pool.getPoolSize());
          System.out.println("core pool size: " + pool.getCorePoolSize());

          for(int i=0; i<10; i++) {
            Future<Void> future = pool.submit(new Callable<Void>() {
              public Void call() throws Exception {
                return null;
              }
            });
            future.get();
            System.out.println("Task " + i + " done");
            System.out.println("pool size: " + pool.getPoolSize());
          }

          pool.shutdown();
        }
      }

      Output:

      initial pool size: 0
      core pool size: 0
      Task 0 done
      pool size: 1
      Task 1 done
      pool size: 1
      Task 2 done
      pool size: 1
      Task 3 done
      pool size: 1
      Task 4 done
      pool size: 1
      Task 5 done
      pool size: 1
      Task 6 done
      pool size: 1
      Task 7 done
      pool size: 1
      Task 8 done
      pool size: 1
      Task 9 done
      pool size: 1


Regards

Heinz
--
Dr Heinz M. Kabutz (PhD CompSci)
Author of "The Java(tm) Specialists' Newsletter"
Sun Java Champion
IEEE Certified Software Development Professional
http://www.javaspecialists.eu
Tel: +30 69 72 850 460
Skype: kabutz


      On 1/17/12 5:51 PM, Vitaly Davidovich wrote:
        That's because you created a fixed size pool; as I mentioned about
core size before, the pool will prefer to add threads in this case to come
up to your core size.  Try with Executor.newCachedThreadPool() instead.

        Sent from my phone

        On Jan 17, 2012 10:40 AM, "Dr Heinz M. Kabutz"
<heinz at javaspecialists.eu> wrote:

          Here's a quick demo:

          import java.util.concurrent.*;

          public class ThreadPoolOnDemandConstruction {
            public static void main(String[] args) throws
ExecutionException, InterruptedException {
              ThreadPoolExecutor pool = (ThreadPoolExecutor)
Executors.newFixedThreadPool(5);
              System.out.println("initial pool size: " +
pool.getPoolSize());

              for(int i=0; i<10; i++) {
                Future<Void> future = pool.submit(new Callable<Void>() {
                  public Void call() throws Exception {
                    return null;
                  }
                });
                future.get();
                System.out.println("Task " + i + " done");
                System.out.println("pool size: " + pool.getPoolSize());
              }

              pool.shutdown();
            }
          }


          Output is:

          initial pool size: 0
          Task 0 done
          pool size: 1
          Task 1 done
          pool size: 2
          Task 2 done
          pool size: 3
          Task 3 done
          pool size: 4
          Task 4 done
          pool size: 5
          Task 5 done
          pool size: 5
          Task 6 done
          pool size: 5
          Task 7 done
          pool size: 5
          Task 8 done
          pool size: 5
          Task 9 done
          pool size: 5


Regards

Heinz
--
Dr Heinz M. Kabutz (PhD CompSci)
Author of "The Java(tm) Specialists' Newsletter"
Sun Java Champion
IEEE Certified Software Development Professional
http://www.javaspecialists.eu
Tel: +30 69 72 850 460
Skype: kabutz


          On 1/17/12 5:24 PM, Vitaly Davidovich wrote:
            I don't have source code in front of me right now but it
shouldn't add threads if there are spare ones unless min or core size was
specified, IIRC.  If one thread can keep up with task submission rate why
create more? For cases where you know you'll have a high rate that outpaces
consumption and don't want to take the hit of waiting for threads to spin
up, you call the pre start method. At least that's what makes sense to me :)

            Sent from my phone

            On Jan 17, 2012 10:15 AM, "Dr Heinz M. Kabutz"
<heinz at javaspecialists.eu> wrote:

              I doubt it.  Threads are created as tasks are submitted, even
if there are threads available.  But maybe you are right :-)

Regards

Heinz
--
Dr Heinz M. Kabutz (PhD CompSci)
Author of "The Java(tm) Specialists' Newsletter"
Sun Java Champion
IEEE Certified Software Development Professional
http://www.javaspecialists.eu
Tel: +30 69 72 850 460
Skype: kabutz


              On 1/17/12 5:11 PM, Vitaly Davidovich wrote:
                Perhaps because you don't know upfront how many threads will
actually be needed to service the workload and thus don't want to spin them
up eagerly (for perf and efficiency reasons) but rather adjust as work comes
in? That is, what if just 1 thread is enough but pool is configured to allow
for more ...

                Sent from my phone

                On Jan 17, 2012 10:06 AM, "Dr Heinz M. Kabutz"
<heinz at javaspecialists.eu> wrote:

                  A quick historical question.  What was the thinking behind
constructing the threads in the ThreadPoolExecutor lazily?

                  In the JavaDocs of ThreadPoolExecutor:

                  On-demand construction
                      By default, even core threads are initially created
and started only when new tasks arrive, but this can be overridden
dynamically using method {@link ThreadPoolExecutor#prestartCoreThread} or
{@link ThreadPoolExecutor#prestartAllCoreThreads}. You probably want to
prestart threads if you construct the pool with a non-empty queue.

                  I can think of two possible answers:

                  Correctness: The author of this class did not want the
ThreadPoolExecutor instance to escape into the threads before it had
completed being constructed.  We should avoid letting "this" escape during
construction.

                  Performance: It might be better to throttle the
construction of new threads.  Say someone creates a new fixed thread pool
with 2000 threads, instead of waiting for them all to be created, we let
each task submission create a thread until we reach the core size.

                  Or perhaps it was neither of these two answers.  Maybe it
was just easier to write it this way, so that one class could be used for
both the cached and the fixed thread pool.

                  Would love to hear the reasons for this :-)

Regards

Heinz
--
Dr Heinz M. Kabutz (PhD CompSci)
Author of "The Java(tm) Specialists' Newsletter"
Sun Java Champion
IEEE Certified Software Development Professional
http://www.javaspecialists.eu
Tel: +30 69 72 850 460
Skype: kabutz

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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20120118/495cf02e/attachment-0001.html>


More information about the Concurrency-interest mailing list