ThreadPoolExecutor - thread creation madness
Hi all,
I am trying to use a Thread Pool for a task server. My testing involves running 10 concurrent jobs that each serially call the server 100 times.
The maximum load on the server (for this test) is therefore 10 tasks at any given point in time. The Thread Pool is creating between 50 and 100 threads to process these tasks. I sent all morning looking at the source and cannot figure out why these threads are being created. Existing threads should be re-used.
The pool is created with 5 core, 100 max threads, 60sec lifetime and a task Q of 5.
The server simply listens to a port (Socket) and calls .execute when a task arrives.
Any ideas why so many threads are being created ?
Thanks,
Craig.
# 1
Here are stats from a run with Core=10, Max=50, Lifetime=60 and Q=6.
The maximum number of threads was reached and tasks were rejected. As per previous post, there was a maximum of 10 concurrent tasks at any given point in time (see Max Act column).
Thread Summary
Max Act (max number of active threads), Max Q (max tasks in Q),
Min/Max PlSz (min/max pool size) are all taken from snapshots while the
reported thread was executing a task.
Times Max Max Min Max1stLast
Thread First UsedLast UsedUsed ActQ PlSz PlSz Task Task
- - -- - -- --
12 2007-07-18 14:36:29 2007-07-18 14:37:1924100105011963
13 2007-07-18 14:36:29 2007-07-18 14:37:2025100105012970
14 2007-07-18 14:36:28 2007-07-18 14:37:192510010503956
15 2007-07-18 14:36:29 2007-07-18 14:37:202610010504983
16 2007-07-18 14:36:29 2007-07-18 14:37:232610010505 1002
17 2007-07-18 14:36:29 2007-07-18 14:37:192510010506962
18 2007-07-18 14:36:29 2007-07-18 14:37:212510010507991
19 2007-07-18 14:36:29 2007-07-18 14:37:202510010508965
20 2007-07-18 14:36:29 2007-07-18 14:37:202710010509975
21 2007-07-18 14:36:29 2007-07-18 14:37:2226100105010 1000
22 2007-07-18 14:36:31 2007-07-18 14:37:2524100115032 1007
23 2007-07-18 14:36:32 2007-07-18 14:37:2022100165046978
24 2007-07-18 14:36:32 2007-07-18 14:37:2021100165047977
25 2007-07-18 14:36:32 2007-07-18 14:37:2022100165048973
26 2007-07-18 14:36:32 2007-07-18 14:37:2022100165049980
27 2007-07-18 14:36:32 2007-07-18 14:37:212493165050992
28 2007-07-18 14:36:34 2007-07-18 14:37:2020100185076968
29 2007-07-18 14:36:34 2007-07-18 14:37:2120100185077989
30 2007-07-18 14:36:34 2007-07-18 14:37:2018100205091976
31 2007-07-18 14:36:34 2007-07-18 14:37:191990205092959
32 2007-07-18 14:36:35 2007-07-18 14:37:22191002250103995
33 2007-07-18 14:36:35 2007-07-18 14:37:21191002250104984
34 2007-07-18 14:36:37 2007-07-18 14:37:24181002350129 1005
35 2007-07-18 14:36:38 2007-07-18 14:37:2115902750162993
36 2007-07-18 14:36:38 2007-07-18 14:37:24181012750163 1004
37 2007-07-18 14:36:38 2007-07-18 14:37:24161002750164 1006
38 2007-07-18 14:36:38 2007-07-18 14:37:20161002750166967
39 2007-07-18 14:36:39 2007-07-18 14:37:20161003250176982
40 2007-07-18 14:36:39 2007-07-18 14:37:2116903250177988
41 2007-07-18 14:36:39 2007-07-18 14:37:20161003250178971
42 2007-07-18 14:36:39 2007-07-18 14:37:21161003250179987
43 2007-07-18 14:36:39 2007-07-18 14:37:20161003250180981
44 2007-07-18 14:36:40 2007-07-18 14:37:1915903350188960
45 2007-07-18 14:36:42 2007-07-18 14:37:21141003750222990
46 2007-07-18 14:36:42 2007-07-18 14:37:2315903750223 1003
47 2007-07-18 14:36:42 2007-07-18 14:37:22151013750225998
48 2007-07-18 14:36:42 2007-07-18 14:37:23141003750226 1001
49 2007-07-18 14:36:43 2007-07-18 14:37:1914904050237961
50 2007-07-18 14:36:43 2007-07-18 14:37:2015914050240974
51 2007-07-18 14:36:43 2007-07-18 14:37:2013804050241972
52 2007-07-18 14:36:44 2007-07-18 14:37:22151034150258996
53 2007-07-18 14:36:45 2007-07-18 14:37:19131004450268958
54 2007-07-18 14:36:45 2007-07-18 14:37:19131004450271957
55 2007-07-18 14:36:45 2007-07-18 14:37:2013904450272969
56 2007-07-18 14:36:45 2007-07-18 14:37:20141004550282979
57 2007-07-18 14:36:46 2007-07-18 14:37:2113804750290985
58 2007-07-18 14:36:46 2007-07-18 14:37:2011704750291966
59 2007-07-18 14:36:47 2007-07-18 14:37:21131004950303986
60 2007-07-18 14:36:47 2007-07-18 14:37:22141014950304997
61 2007-07-18 14:36:47 2007-07-18 14:37:19121005050316950
Maximum size pool reached was 50
*** End of Report ***
# 2
I need some source code to look into this problem. The only thing I can come up with right now is that you initialize a new ThreadPool for every single instance of you're worker class. In short: Post some code !!
# 3
Here is the server start and process code - quite simple stuff.
public static void main(String[] args) {
System.out.println(getTimestamp() + "Starting " + _fullServerId);
log(TRACE_INFO, "Starting " + _fullServerId);
System.out.println(getTimestamp() + "Trace level is " + getTrace());
System.out.println(getTimestamp() + "Thread Pool Core Size is " + getThdPoolCoreSize());
System.out.println(getTimestamp() + "Thread Pool Max Size is " + getThdPoolMaxSize());
System.out.println(getTimestamp() + "Thread Lifetime is " + getThdLifetime() + " seconds");
System.out.println(getTimestamp() + "Task Queue Size is " + getTaskQueueSize());
// create the blocking queue to hold waiting tasks
System.out.println(getTimestamp() + "Creating the Task Queue");
_blockingQueue = new ArrayBlockingQueue<java.lang.Runnable>(getTaskQueueSize());
// create the thread pool
System.out.println(getTimestamp() + "Creating the Thread Pool");
_threadPool = new ThreadPoolExecutor(
getThdPoolCoreSize(),
getThdPoolMaxSize(),
getThdLifetime(),
TimeUnit.SECONDS,
_blockingQueue);
_threadPool.allowCoreThreadTimeOut(false);
System.out.println(getTimestamp() + "Prestarting the core threads");
_threadPool.prestartAllCoreThreads();
System.out.println(getTimestamp() + "Server initialized and waiting for tasks...");
log(TRACE_INFO, "Server initialized and waiting for tasks...");
try {
processCommands();
} catch (Exception e) {
System.out.println("");
System.out.println("Unable to start/stop " + _fullServerId);
System.out.println("");
log(TRACE_FATAL, "Unable to start/stop " + _fullServerId, e);
}
}
/**
* Creates a Socket and listens for requests. When a request comes in it is
* handed over to the thread pool for execution.
*
*
When a STOP command is received, the server closes down.
*
* @throws java.lang.Exception Passes exception up the chain.
*/
private static void processCommands() throws Exception {
String service;
ServerSocket ss = new ServerSocket(getPort());
try {
while (true) {
Socket sock = ss.accept();
if (++_taskId >= Long.MAX_VALUE - 2) {// well, you never know... :)
_taskId = 1;
}
try {
BufferedInputStream in = new BufferedInputStream(sock.getInputStream());
BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream());
N2JServerTask task = new N2JServerTask(_taskId, sock, in, out);
service = task.getService(); // we need to check for a STOP command
try {
_threadPool.execute(task);// start task asap
} catch (RejectedExecutionException ree) {
_rejectedTasks++;
dmPutData(_returnData, (byte) 1);// no response - error follows
dmPutData(_returnData, POOL_FULL_ERROR);
dmPutData(_returnData, ree.toString());
log(TRACE_WARN, _taskId + ": Thread Pool Error: Code = " + POOL_FULL_ERROR +
", Msg = " + ree.toString());
log(TRACE_DEBUG, _taskId + ": Writing RC and Message to stream");
out.write(_returnData.toByteArray()); // Return code & message
out.flush();
out.close();
in.close();
sock.close();
log(TRACE_DEBUG, _taskId + ": Task Rejection Reported to Client.");
}
if (service.equalsIgnoreCase(SERVICE_STOP)) { // shutdown requested...
try {
System.out.println("");
System.out.println(getTimestamp() +
"Server shut down request received. Shutting down...");
_threadPool.shutdown();
Thread.sleep(getShutdownWaitTime() * 1000); // wait for existing threads to complete...
int numTasks = _threadPool.getActiveCount();
if (numTasks != 0) {
System.out.println(getTimestamp() + numTasks + "tasks still active. Terminating remaining tasks...");
log(TRACE_WARN, numTasks + "tasks still active. Terminating remaining tasks...");
_threadPool.shutdownNow();
}
} catch (Exception e) {
System.out.println("Error during shutdown...");
log(TRACE_ERROR, "Shutdown Error: ", e);
} finally {
break; // escape from loop
}
}
} catch (Exception e2) {
log(TRACE_ERROR, "Internal Error: ", e2);
}
} //end-while
} catch (Exception e3) {
log(TRACE_ERROR, "Internal Error: ", e3);
} finally {
ss.close();
}
System.out.println("");
System.out.println(getTimestamp() + _fullServerId + " Ended.");
log(TRACE_INFO, _fullServerId + " Ended.");
log(TRACE_INFO, "...");
}
So I am not creating more than one thread pool. I try to keep the code as standard (using available API's) and simple as possible.
If you need more details, let me know.
# 4
The question was whether your Task created a new thread, not a new thread pool.
But there are other problems here. You shouldn't do any I/O whatsoever on accepted sockets in the accepting thread, otherwise you are running a major risk of hanging the server. You shouldn't even create the input and output streams. All that stuff should be moved into the service task. If you can't start the service task that also means you can't log anything to the accepted socket: just close the accepted socket and forget about it.
ejpa at 2007-7-29 13:14:49 >

# 5
first of all the next line is complete misplaced
if (service.equalsIgnoreCase(SERVICE_STOP)) { // shutdown requested...
service comes from the N2JServerTask which runs in another Thread. You start the N2JServerTask Thread (the pool does this for you) and immediately you ask the this service object if the N2JServerTask wants the server to shutdown. This is completely wrong, because you do not know if the N2JServerTask already started (the Thread system could decide to wait before executing yout N2JServerTask Thread). Second problem is that you only ask it once for every service here (I can not browse your N2JServerTask, but these kind of requests should be handles there)
Since I can not see your N2JServerTask I can not be sure if this code finishes correctly. It could be that these N2JServerTask instances do not finish correctly (if you post that code as well I will probably be able to tell you).
Also be aware that for each Socket the system (can) open some threads in the background. These threads will not be part of your threadpool, but if you do a JVM threaddump you will see them.
Last but not least .. you should consider using NIO. The SocketServer.accept() is a blocking call and does not really allow your application for a clean shutdown (you probably need Thread.interrupt() to break these kind of calls... and these kind of calls should be avoided)
# 6
There are some issues here, but none of these have anything to do with the thread creation madness I am seeing.
The who should do what is a catch 22. We require that all callers get a response (barring network failure). The callers and server are all on an internal network, no WWW involved. If a call is rejected I need to tell the caller that the task could not be started, not just leave it hanging.
Also see my response to the reply after yours...
Thanks,
Craig.
# 7
> service comes from the N2JServerTask which runs in
> another Thread.
It's RUN method is invoked in another thread. This method is executed in the server's thread.
This is a long post. For the 'thread' issue skip down "Thread Issue" at the end...
I have given some thought to doing the service check in the other thread, but then it would have to be able to interrupt the server to tell it that a shutdown request has been issued. Time for this later...
Again, I have gotten some useful coding advice, but nothing which starts to explain the thread creation madness.
N2J is a RPC implementation that allows remote procedure calls between a 4th Gen language (Natural) running on a mainframe and Java.
N2JServerTask is a utility task that does the following:
1. read the initial information coming from the input stream.
2. load the requested service
3. perform the data marshaling of the request data (from the stream), loading it into a ArrayList.
4. call the services' process method to get the real work done.
5. perform the data marshaling of the response data, return code etc.
6. handle exceptions thrown by the service
7 clean up and go home.
EDCDIC / ASCII translation is handled on the mainframe.
This initial version of this has been running in production for a year - no problems. However, the initial version created a new thread for every request - which was OK because call volume was low. We now have a high volume application on the horizon - hence the move to try and optimize using pooling.
N2JServerTask does finish OK - the threads are all being reused - there are simply too many of them. N2JServerTask has enough try/catch and logging going on so I know it is running OK. You can trust me on this.
Thread Issue
============
The issue, as I see it is is a timing one:
The worker tasks in the thread pool issue a poll to the task queue when they are looking for work. The task Q uses a ReentrantLock(fair) to queue threads waiting for work.
When the execute() method is called, it adds the task to the task Q, then signals the ReentrantLock. The server is somehow managing to fill the task Q before any polling thread is able to respond to the signal, causing a new thread to be allocated.
I tried to follow the locking processes (made my head hurt) because I believe that there is a synchronization problem here.
So the real question is why is the task Q being filled before polling threads are able to pull tasks off the task Q.
Given that the server is doing IO over a socket one would think there would be plenty of opportunity for the Q to be drained.
One last point - Using task manager under windows, I see that my CPU (single CPU laptop) is not working very hard at all during the test - averaging around 10%. So there are plenty of CPU cycles available. Could the fact that there is only one CPU contribute to the problem ?
Sorry for the long post, but this is killing me...
Craig.
Message was edited by:
javadude.101
# 8
> server is somehow managing to fill the task Q before
> any polling thread is able to respond to the signal,
> causing a new thread to be allocated.
The other threads are apparently waiting or busy ..
> I tried to follow the locking processes (made my head
> hurt) because I believe that there is a
> synchronization problem here.
Did you put the word synchronized in your own code ? If not then I doubt that there is a synchronization problem...
> Given that the server is doing IO over a socket, one
> would think there would be plenty of opportunity for
> the Q to be drained.
You are completely confusing me here :S .. AFAIK doing IO over a socket means a Thread is busy handling this IO (assuming your not using NIO). This IO handling is not done by the thread that's accepting connections so it must be one of the threads in your 'Executor Service'. Let's say you are reading a byte array of 100 bytes using the inputStream.read(data) where data is you byte Array. If the network is very busy and only one byte per second comes true then this method call will block the Thread for 100 seconds. During this whole period of 100 seconds this thread is NOT available to process other tasks... the thread will have the status WAIT until the 100 bytes are read (or EOF is received, or the socket is being closed). Your 'Executor Service' will have this thread marked as something like 'IN USE'.
> One last point - Using task manager under windows, I
> see that my CPU (single CPU laptop) is not working
> very hard at all during the test - averaging around
> 10%. So there are plenty of CPU cycles available.
> Could the fact that there is only one CPU contribute
> to the problem ?
Threads in a waiting state do not occupy processing time. Your tasks are probably waiting indefinitely for incoming/outgoing data. But it could also be a synchronization problem (but is seriously doubt that). That there is only one real CPU should theoretical not matter as long as you're not running on an ancient machine running something like windows 95 or dos 2.0 (or maybe even older the C64 ;)
> Sorry for the long post, but this is killing me...
That's fine .. so are my responses. BTW if you want your problem to get solved then post the run method of the N2JServerTask (at least the parts that should be important)
# 9
> Did you put the word synchronized in your own code ?
No.
>
> > Given that the server is doing IO over a socket,
> You are completely confusing me here :S
Sorry, what I meant was that the server is paused, waiting for a request. Other threads should have all the time they need to pick up waiting tasks from the Q.
> Your tasks are probably waiting indefinitely
> for incoming/outgoing data.
No. I will modify the log writes and make the log available. That way we can track each thread's activity and see that in relation to when new threads get created. I'll post a link to the log when it's done.
> BTW if you want
> your problem to get solved then post the run method
> of the N2JServerTask (at least the parts that should
> be important)
Here ya go...
/**
* This method gets the User's credentials, loads the required service,
* retrieves the data from the input stream and then calls the service's
* process() method.
*
When the service has completed, the response is returned to the
* client.
*
All exceptions are handled. Errors are returned to the client.
*/
public void run() {
String loadService;
try {
try {
// set up for local commands (PING, TRACE, STATUS and STOP)
if ((_service.equalsIgnoreCase(SERVICE_STOP)) ||
(_service.equalsIgnoreCase(SERVICE_PING)) ||
(_service.equalsIgnoreCase(SERVICE_STATUS)) ||
(_service.equalsIgnoreCase(SERVICE_TRACE))) {
loadService = N2JLocalService.class.getName();
} else {
loadService = _service;
}
// Credentials
getCredentials();
// Load the requested service
log(TRACE_INFO, _taskId + ": Service Request: User=" + _user +
", Service=" + _service);
N2JServiceInterface serviceClass =
(N2JServiceInterface) Class.forName(loadService).newInstance();
log(TRACE_DEBUG, _taskId + ": Service " + _service + " loaded");
try {
// Get it ready to go
serviceClass.setServerThread(this);
serviceClass.setId(_taskId);
serviceClass.setUser(_user);
serviceClass.setClientData(getInputData());
// Hand over control
log(TRACE_DEBUG, _taskId + ": Calling service's 'Process' method");
serviceClass.process();
// Send the response back to the client
log(TRACE_DEBUG, _taskId + ": Writing data to stream");
_outputStream.write(0);// Response follows
_outputStream.write(_returnData.toByteArray());
_returnData.reset(); // for finally clause
putData((int) 0);// 'OK' return code
putData(""); // 'OK' return message
} catch (N2JServiceException se) { // thrown by service process method
_returnData.reset(); // for finally clause
putData((byte) 1);// no response - error follows
putData(se.getReturnCode());
putData(se.getReturnMsg());
log(TRACE_INFO, _taskId + ": Service Error: Code = " +
se.getReturnCode() + ", Msg = " + se.getReturnMsg());
}
} catch (Exception e) {// all other errors
_returnData.reset();
putData((byte) 1);// no response - error follows
putData(SYSTEM_ERROR);
putData(e.toString());
log(TRACE_WARN, _taskId + ": System Error: Code = " + SYSTEM_ERROR +
", Msg = " + e.toString(), e);
} finally {
log(TRACE_DEBUG, _taskId + ": Writing RC and Message to stream");
_outputStream.write(_returnData.toByteArray()); // Return code & message
_outputStream.flush();
_outputStream.close();
_inputStream.close();
_sock.close();
log(TRACE_DEBUG, _taskId + ": Thread Finished.");
}
} catch (Exception e) {
log(TRACE_ERROR, _taskId + ": System Error: Code = " + SYSTEM_ERROR +
", Msg = " + e.toString(), e);
e.printStackTrace();
}
}
# 10
Apart from that your style of programming is not my preferred style, I don't see something really bad here. But that could be because the interesting stuff is either in the call service(); or in the Log files you will post (i'm really curious about these logs :)
# 11
OK, here is the log from a run where 28 threads were created to execute a maximum of 10 concurrent tasks.
The service tasks are all the same - it is a test task that does nothing other than simple arithmetic and a few 'if' statements. It does no IO of any sort. It is not significant in this test, taking a few milliseconds to execute.
The first 101 tasks executed in the 5 core threads. That shows how quickly the tasks are executing.
Task # 189 is the first that uses a thread that is not a core thread. The stats tell the picture from there.
Log File: http://www.3dpilots.com/java/N2J_Devp.txt
Threads Stats File: http://www.3dpilots.com/java/ThreadStats.txt
The thread start and end messages are the first and last statements that are executed in the run() method.
Regards,
Craig.
# 12
Hey JavaDude,
I looked at your question, but I think the threadpool is working correctly.
First of all, your thread life time is quite high (60 seconds). Thread life time is only used for excess threads. Its kind of the keep-alive value after they have been created because the thread pool thought it was needed. The tread pool is free to reuse these threads as it pleases as long as they are alive. So, I would suggest to lower this number to something like a few seconds (maybe even less). Excess threads should be cleaned up more quickly.
Second of all, the check-in process of the threads is a synchronized happening. It might be that mutliple threads are waiting to enter the blocking queue (does not equial to waiting for something in the queue). So, even though your logging says that the execution is complete, it does not mean that the thread has completed running and is waiting for the next task.
Unfortuantly I don't think there is much you can do about it. Lots of short task will cause this problem. My suggestion is to tweak the thread life time, see if that helps, and just expect the thread count to become high.
# 13
I think I finally understand your problem (ufh .. that took a while ;). As I see it your problem is in the finalization of a server request. Their is a short time between the last byte the server sends and the real ending of the thread. This time is filled with closing the streams and closing the socket. Closing these things may get delayed for different reasons. If I'm correct the next points might be of interest:
1. if you run a 'netstat -a -n' in a terminal/dos-prompt on the server while it's handling the client requests, then you might get to see more then 10 connections from the client. Where probably some are in the state 'CLOSING' or 'TIME_WAIT'.
2. if you would run only one thread on the client you might get the same effect.
3. if you would run only one thread but add an delay between the request, then the effects might get less and/or even disappear. The same may be true for running all 10 clients.
I also would like to know which OS and version of JDK/JRE you are running on the server. If none of the above has any effect then my guessing was wrong :(, if so let me know and send me some more logs.
Regards,
Douwe Vos
# 14
Thanks for the reply.
> First of all, your thread life time is quite high (60
> seconds). Thread life time is only used for excess
> threads. Its kind of the keep-alive value after they
> have been created because the thread pool thought it
> was needed. The tread pool is free to reuse these
> threads as it pleases as long as they are alive. So,
> I would suggest to lower this number to something
> like a few seconds (maybe even less). Excess threads
> should be cleaned up more quickly.
Quite right. I tried with a 1 second lifetime and got a maximum of 10 threads active at any one time. The total number created was 106. Not ideal, but I will play with the lifetime and find what works best.
Another interesting thing was that my core stayed at 5. With a long lifetime, there is a bug that caused my core threads to get thrown away after a burst of activity. I have the pool set to not delete core threads, but it was doing it anyway under those conditions, but not now.
> Second of all, the check-in process of the threads is
> a synchronized happening. It might be that mutliple
> threads are waiting to enter the blocking queue (does
> not equial to waiting for something in the queue).
> So, even though your logging says that the execution
> is complete, it does not mean that the thread has
> completed running and is waiting for the next task.
Sound feasible. I always thought this was a timing issue.
> Unfortuantly I don't think there is much you can do
> about it. Lots of short task will cause this problem.
> My suggestion is to tweak the thread life time, see
> if that helps, and just expect the thread count to
> become high.
Thanks. I will post what I find to be a good lifetime.
I also tried slowing the tasks down. First test with a 1 second sleep and everything executed in far fewer threads than I expected. I need to look at that a bit more too.
Regards,
Craig.
# 15
Interesting ...
I got up to a thread lifetime of 3 and things seemed OK. Then I added a 1/2 second delay to the task using Thread.sleep. Ran with Core=10, Q=5, Life=3
Largest pool size was 30, maximum number of active threads was 9. The core threads were killed. It went down to one thread after the test. Total of 83 threads created; +-1005 tasks executed.
Changed the lifetime to 2.
Largest pool size was 24, maximum number of active threads was 9. The core threads were not killed. Total of 116 threads created; +-1005 tasks executed.
Changed the lifetime to 1.
Largest pool size was 15, maximum number of active threads was 9. The core threads were not killed. Total of 105 threads created; +-1005 tasks executed.
I now need to see what the total throughput time is versus what I was doing, creating a thread for every task. My N2JServerTask was a Thread, and is now a runnable. My expectation is that performance was better without the pool - because I still have to instantiate N2JServerTask for every task.
I may try a simple pool implementation where I create N2JServerTask (as a Thread) in a thread factory, then pool and reuse those. Anyone got a link to some robust Pool code I can see ?
Thanks,
Craig.
# 16
You might need to use a bit of elementary queueing theory on this. If you specify your thread pool so that it can get over 70% busy the wait times can increase exponentially, e.g. they double between 70% and 80% and double again between 80% and 90%. 70% is the sweet spot.
ejpa at 2007-7-29 13:14:55 >

# 17
These are the timing results with and without Thread Pooling.
End:2007-07-25 09:24:36,014Pooled: Core=10; Max=50; Life=2; Q=5
Start: 2007-07-25 09:23:44,315Max PoolSize Reached=24, Total of 130 Thds created.
Difference:0:51,699Total test elapsed time with thread pooling.
End:2007-07-25 09:41:38,418No Pooling: 1000 threads created.
Start: 2007-07-25 09:41:09,467
Difference:0:28,951Total test elapsed time without thread pooling.
Kind of makes you wonder...
I have ordered a few books to study this further, but I will probably write my own pool to try and get better than 20 second throughput. Reusing N2JServerTask (as a thread instead of a runnable) should accomplish this.
Regards,
Craig.
Message was edited by:
javadude.101
# 18
> Kind of makes you wonder...
Kind of makes you wonder what? I would expect non-thread-pool model, effectively an unlimited thread pool, to service a large number of requests faster than a thread pool.
But I think you're approaching the problem from the wrong end. Usually you are worried about response time contracts and adjusting your server, your thread pool if any, and/or your hardware accordingly. All this focus on how many threads were created seems completely misplaced to me.
ejpa at 2007-7-29 13:14:55 >

# 19
> First of all, your thread life time is quite high (60
> seconds). Thread life time is only used for excess
> threads. Its kind of the keep-alive value after they
> have been created because the thread pool thought it
> was needed. The tread pool is free to reuse these
> threads as it pleases as long as they are alive. So,
> I would suggest to lower this number to something
> like a few seconds (maybe even less). Excess threads
> should be cleaned up more quickly.
Call me stupid .. but Thread creation is an expensive task. Reusing Threads is much better then killing them and creating new ones. So a lifetime of one second will more or less kill the thread after running one task (I'm confused here ... in my opinion this can't be effective)