The Source for Java Technology Collaboration
User: Password:
Register | Login help    

Search

Online Books:
java.net on MarkMail:


A bug in the ThreadPoolExecutor

Posted by rexyoung on November 11, 2007 at 9:57 AM PST

Jsasb actor follows message-passing model. There are two kind of messages: event and request. An event is an async-message that is the primary message in the Jsasb. While a request is a sync-message that is a supplement to events for easy design and efficiency in some situations.

For this purpose, I designed a flexible thread pool to deliver asyc-messages. The JDK (or say Doug's) ThreadPoolExecutor supports two modes. One is to have a core size pool with a maximum size. It rejects tasks when the pool size reaches the maximum. The other is a fixed size pool and an unlimited task queue.

I did not like either one. I wanted both of them. So I digged into source code, and found that ThreadPoolExecutor schedules threads using a queue style storage rather than a stack. A thread finished a task is returned to the queue and won't get another chance to run until all other threads had a run. As a resule, ThreadPoolExecutor will shutdown idle threads only when no new tasks at all. It can not detect light workload in which a few tasks come in constantly like a timer task.

Unfortunately, ThreadPoolExecutor is a key and complex class in Java concurrency. I did not think it would be a good idea to write my own ThreadPoolExecutor. So I did two things. I subclassed ThreadPoolExecutor and made my org.jsasb.execution.RangedThreadPool to support both modes. RangedThreadPool first try to increase the pool size for new tasks, then store new tasks to an unlimited task queue when the maximum pool size is reached. This class is a general utility class that is not specified for Jsasb only. You may make a use of it if you like.

The second thing was that I filed a bug report to Sun. But did not hear anything. Maybe they do not think this is a big deal.

I listed the bug report below. You can verify and reproduce it using the code in the report.
====================================================================
Your Report (Review ID: 934994) - ThreadPoolExecutor cannot 1) detect light workload 2) bring down excess threads.
IncidentDaemon@sun.com Wed, Mar 28, 2007 at 4:35 PM
To: rexyoung@users.sourceforge.net
************************************************
Dear Java Developer,

Thank you for your interest in improving the quality of Java Technology.

Your report has been assigned an internal review ID of 934994, which is NOT visible on the Sun Developer Network (SDN).

Please be aware that the large volume of reports we receive sometimes prevents us from responding individually to each message.

We currently have a three week average response time. If the information is determined to be a new Bug or RFE, or a duplicate of a known Bug or RFE, you will receive a followup email containing a seven digit bug number. You may search for, view, or vote for this bug in the Bug Database at http://bugs.sun.com/.

If you just reported an issue that could have a major impact on your project and require a timely response, please consider purchasing one of the support offerings described at http://developers.sun.com/services/.

The Sun Developer Network (http://developers.sun.com) is a free service that Sun offers. To join, visit http://developers.sun.com/global/join_sdn.html.

For a limited time, SDN members can obtain fully licensed Java IDEs for web and enterprise development. More information is at http://developers.sun.com/prodtech/javatools/free/.

Thank you for using our bug submit page.

Regards,
Java Developer Bug Report Review Team

---------------------------------------------------------------

Date Created: Wed Mar 28 17:35:18 MST 2007
Type: bug
Customer Name: Rex Young
Customer Email: rexyoung@users.sourceforge.net
SDN ID: rexyoung
status: Waiting
Category: java
Subcategory: classes_util
Company:
release: 5.0
hardware: x86
OSversion: win_xp
priority: 4
Synopsis: ThreadPoolExecutor cannot 1) detect light workload 2) bring down excess threads.
Description:
FULL PRODUCT VERSION :
JDK 5/6/7

ADDITIONAL OS VERSION INFORMATION :
All platforms.

A DESCRIPTION OF THE PROBLEM :
ThreadPoolExcecutor can create new threads up to maximum pool size when there are lots of tasks coming in. And it can shutdown idle threads when no task comes in. But it can not detect light workload in which a few small tasks consistently come in. Because all threads wait on a queue, they execute a small task a time rotationally in this case. Hence the pool thinks it is very busy and no thread considered as excess thread.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Please see test case.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Excess threads should be shutdown.
ACTUAL -
All threads are alive and execute small task by turns.

REPRODUCIBILITY :
This bug can be reproduced occasionally.

---------- BEGIN SOURCE ----------

package org.jsasb.execution;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Test implements Runnable {

       public static void main(String[] args) throws Exception {
               ThreadPoolExecutor pool = new ThreadPoolExecutor(
                               1, 10, 60, TimeUnit.SECONDS,
                               new ArrayBlockingQueue(1));

               Test task = new Test();

               for(;;) {
                       try {
                               pool.execute(task);
                       } catch (Exception e) {
                               break;
                       }
               }

               for(;;) {
                       Thread.sleep(1000);
                       pool.execute(task);
               }
       }

       static int count = 0;
       static synchronized int getCount() {
               return count++;
       }

       public void run() {
               try {
                       System.out.println(getCount() + " -- "
                                       + Thread.currentThread().getName());

                       Thread.sleep(250);
               } catch (Exception e) {
               }
       }

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
May use two instances of ThreadPoolExecutor. One has a pool in small size. Tasks are first delivered to this pool. When it is full and starts to reject task, submit it to the second pool in a bigger size.

This way excess threads in the second pool has a chance to cool down as the first pool takes care of those small tasks.
workaround:
comments: (company - , email - rexyoung@users.sourceforge.net)

Related Topics >> Programming      
Comments
Comments are listed in date ascending order (oldest first)