Tomat Component Research Threadpool
I promised you a few days ago to complete the article of thredpool, Tomcat SSL, and today I have time to write a little. Tomcat's Thradpool is different from Apache's CommON Thradpool. Tomcat's ThreadPool is specifically for Tomcat service, which is exactly the HTTP connection service for Tomcat. After study, Apache wrote these threePool classes with its difficulties and concealed methods, although only a few classes, but it is an amazing level. After understanding, it is really worth learning, but there are many useless things. It seems that we should not blindly worship Apache. Less nonsense, directly below the topic.
Threadpool Class and Overall Structure:
One. Description of each class:
1. Org.apache.tomcat.util.threads.threadpool
Thread pool class, this class only maintains a certain number of thread processing objects, and puts the task of the specific execution operation to other objects, Apache does not give too much function to this class, but only let this type of maintenance The creation, destruction, removal, and return of threads. Let's see the code of this class:
Public class threadpool {
(1) Thread pool constant, the corresponding variable setting is no longer listed.
// Maximum thread
Public static final int max_threads = 200;
// Minimum number of maximum threads (the maximum number of threads cannot be less than this)
Public Static Final Int Max_threads_min = 10;
// Maximum idle thread
Public static final int max_spare_threads = 50;
// Minimum idle thread number (so many threads starting when the thread pool is initialized)
Public Static Final Int min_spare_threads = 4;
// Maximum waiting time (1 minute)
Public Static Final Int Work_Wait_timeout = 60 * 1000;
(2) START method
/ / For each thread instance this method is only called once
Public synchronized void start () {
/ / Whether to stop the thread
Stopthepool = false;
// The current number of threads currently generates
CurrentThreadCount = 0;
// The number of current use threads
CurrentThreadsbusy = 0;
// If the various parameters of the current setting are incorrect, adjust it
Adjustlimits ();
/ / Generate empty thread pool
Pool = New Controlrunnable [Maxthreads];
// Start the minimum line number thread
OpenTHREADS (Minsparethreads);
// Start the monitoring thread, monitor the internal state of the thread pool
Monitor = new monitorRunnable (this);
}
(3) OpenTHREADS method
/ **
* Start the specified quantity (TOOPEN) thread
* This method is very strange, this TOOPEN is not the number of threads opened this time.
* Is the sum of threads that have been opened for this time and previously opened.
* /
Protected void OpenTHREADS (int toolen) {
IF (TOOPEN> MAXTHREADS) {
TOOPEN = Maxthreads;
}
// The newly opened thread is placed behind the existing idle thread (stored with array)
For (INT i = CurrentThreadCount; i Pool [i - currentthreadsbusy] = new Controlrunnable (this); } CurrentthreadCount = TOOPEN } Here we feel that apache's approach is strange. First of all, there is a point, when we write the connection pool, use List as a container, generally have a current number of idle threads, but the Apache bias is used as a container to store Threads, with arrays to maintain each thread (new, used, idle) in the subscript in array, if you use list, we will be Get, Add, Remove, everything is OK, it is very convenient . Because there is CurrentThreadsbusy, the current number of idle threads of Apache must be calculated using CurrentThreadCount- CurrentThreadsbusy. Why do we see the strange cycle above? But what is the benefit of using the array, or the people of Apache are pig heads (relying on, they can't be a pig head)? We may find that there is a constant above: // Maximum thread Public static final int max_threads = 200; That is, the default maximum pool can have 200 threads, that is, there are many threads that may be frequent from the pool. Take, place the thread, if you use List efficiency, you will use an array. (4) FindControlRunnable method, get a usable thread Private controlrunnable FindControlrunnable () { Controlrunnable C = NULL; IF (stopthepool) { Throw new IllegalStateException (); } // Take an available thread from the pool. Synchronized (this) { / / All current threads are used While (currentthreadsbusy == currentthreadcount) { // The current number of threads is less than the maximum number of threads CurrentthReadcount / / Generate a certain amount (Minsparethreads) thread, this point // We are very different when we do connecting pools, and we often generate a new connection. // Connect, it seems that Apache is really worth learning Int toopen = CurrentThreadCount Minsparethreads; OpenTHREADS (TOOPEN); } else { Logfull (log, currentthreadcount, Maxthreads; // If all threads (maximum number have been to the maximum), wait for other lines / Cheng release. Try { THIS.WAIT (); } catch (interruptedexception e) { Log. Error ("Unexpected Exception", E); } // pool WAS Stopped. Get away of the pool. IF (stopthepool) { Break; } } } // pool WAS Stopped. Get away of the pool (0 == CURRENTTHREADCOUNT || stopthepool) { Throw new IllegalStateException (); } INT POS = CURRENTTHREADCOUNT - CURRENTTHREADSBUSY - 1; // After tossing, I finally have an idle thread in the thread pool, and below // The last thread in the group C = pool [POS]; / / Release When the front thread pool is referenced to the thread Pool [POS] = NULL; // Of course, use the number of threads to add 1 CurrentThreadsbusy ; } Return C; } We can see this method: Ø All in the thread pool is all idle threads Ø The newly generated thread is placed behind the existing thread (queue) Ø When you take a thread, get the last available thread on the queue. Ø When the thread is taken out, the queue releases the reference to the thread, and uses the thread variable plus 1. Ø Thread pool to use thread maintenance only through the currentthreadsbusy variable has been implemented (5) ReturnController method, returning a thread object to the pool This method is still a good understanding Protected Synchronized Void ReturnController (Controlrunnable C) { IF (0 == CurrentThreadCount || stopthepool) { C.TERMINATE (); Return; } // Use thread reduction 1 CurrentThreadsbusy -; // Put the release thread in the idle thread leader Pool [CurrentThreadCount - CurrentThreadsbusy - 1] = C; / / Wake Waiting Warm, telling them that there is available thread, don't be stupid, etc. NOTIFY (); } Here we see this, use array as a container storage cable and complicated, always carefully operate the subscript of arrays, but there is no way, or this is too efficient. (6) RUNIT method This seems ugly small method, but the entrance to the Tomat Threadpool Essence, which is the interface that is provided to other components to participate in the internal operation of the thread pool. When there is an HTTP request coming in, Tomcat generates a working thread and then incorporates this method. Public void Runit (ThreadPoolRunnable R) { IF (NULL == R) { Throw new nullpointerserException (); } / / Find a specific task of available idle threads ControlRunnable C = FindControlrunnable (); C.Runit (R); } (7) SHUTDOWN method, turn off the thread, release resources Public synchronized void shutdown () { IF (! stopthepool) { Stopthepool = true; // Stop listener Monitor.Terminate (); Monitor = NULL; // Release the idle thread For (int i = 0; i <(CurrentThreadCount - CurrentThreadsbusy - 1); i ) { Try { Pool [i] .Terminate (); } catch (throwable t) {log.error ("Ignored Exception While Shutting Down Thread Pool", T); } } // Reset Use Thread Use Sign Currentthreadsbusy = currentthreadcount = 0; Pool = NULL; NotifyAll (); } } As we said, using thread maintenance is only via the currentthreadsbusy variable, so it can not be recycled on the thread objects that have been used, and only CurrentThreadsbusy = 0 can only be set. 2. Org.apache.tomcat.util.threads.monitorRunnable This class only has the purpose of maintaining the number of threads of the thread pool. Seeing that we not only blame the Apache practice, why do you want to make a thread to maintain the number of threads? In fact, the maintenance of threads in the thread pool can be placed in the FindControlrunnable and ReturnController method, but because of the frequent calls of these two methods, it has an impact on efficiency, and therefore, it is considered in terms of efficiency. (1) RUN method Public void run () { While (true) { Try { // Waiting for a specified time, or wake up this thread when it is returned Synchronized (this) { THIS.WAIT (Work_Wait_Timeout); } //stop. IF (shopterminate) { Break; } // Call the thread pool method for thread maintenance. p.checkspareControllers (); } catch (throwable t) { ThreadPool.log.Error ("Unexpected Exception", T); } } } (2) CheckspareControllers method This method belongs to the ThreadPool class, called the RUN method of the MonitorRunnable class. Protected synchronized void checksparecontrollers () { IF (stopthepool) { Return; } // The current number of idle threads is greater than the maximum idle thread, release excess thread IF (CurrentThreadCount - CurrentThreadsbusy> MaxSparethreads) { / / The number of threads that should be released INT TOFREE = CURRENTTHREADCOUNT - CurrentThreadsbusy - Maxsparethreads; For (int i = 0; i Controlrunnable C = Pool [CurrentThreadCount - CurrentThreadsbusy - 1]; C.TERMINATE (); // Release from the back Pool [CurrentThreadCount - Currentthreadsbusy - 1] = NULL; // Thread number reduction 1 CurrentThreadCount -; } } } Through this method, we have to grasp two points: Ø Release the idle thread, press the order from the back forward Ø The number of total threads should be reduced when the release thread is released. 3. Org.apache.tomcat.util.threads.Controlrunnable This class is a static thread class that stores instances of this class in the thread pool. This class is mainly used to perform a wide variety of operations inside the thread pool. (1) Constructor ControlRunnable Controlrunnable (threadpool p) { Torun = NULL; // Stop sign Shouldterminate = false; // Run the flag, the thread does not run when constructed the function Shouldrun = false; THIS.P = P; // Time-threaded local data operation, THREADWITHATTRIBUTES will later introduce T = New Threadwithattributes (p, this); T.SETDAEMON (TRUE); T.setName (p.GetName () "-processor" p.getSequence ()); // Start Thread Threadwithattributes T.Start (); / / Add thread to the pool P. ADTHREAD (T, THIS); NothData = true; } It can be seen that the constructor has completed the following functions: Ø Construct Threadwithattributes object with threaded pool objects P and itself (this) Threadwithattributes is used to replace Threadlocal objects. Its role is localization of thread data, avoiding access conflicts between threads, so that it controls access to thread properties to prevent untrusted code access threads. Data, we will explain the specific explanation below. Ø Start Threadwithattributes thread Ø Add thread to the pool Here we can see that the thread in the thread pool is placed in two different places: Thread pools maintained by array and Threads objects maintained by HashTable: Protected Hashtable Threads = new hashtable (); Key: Threadwithattributes object Value: ControlRunnable object Increase the thread to the pool will cause calls to the following methods: (2) Addthread, RemoveThread method Public Void Addthread (Thread T, Controlrunnable CR) { Threads.Put (T, CR); For (int i = 0; i Threadpoollistener TPL = (Threadpoollistener) listeners.ementatat (i); // Notify the listener, have a thread join TPL.ThreadStart (this, t); } } Public void RemoveThread (thread t) { Threads.Remove (T); For (int i = 0; i Threadpoollistener TPL = (Threadpoollistener) listeners.ementatat (i); / / Notify the listener, have a thread being deleted TPL.THREADEND (THIS, T); } } Seeing this method, we may recall a lot of places to use Listener to handle some, what is Listener? In fact, we will find it carefully and will find that use the Listener to use the OBServer mode of the GOF23 model. (3) About OBSERVER mode The above is a general OBServer mode class map. If Subject does not use the interface, use a class and put the meaning of the Subject's meaning, it is not a partial property for all the properties, then Subject is actually our ThreadPool class, Observer In fact, it is a Listener interface. The observed object is the Threads of the Threadpool class. When THReads makes PUT, Remove calls all Listener methods that are registered to the Threadpool class, that is, AddThread, RemoveThread. The intention of the OBServer mode is to establish a pair of dependencies between the objects. When an object is changed, all objects that depend on its object can be notified and can be automatically updated. (4) Java's OBServer mode In fact, Java has integrated Observer mode into the language, class java.util.observable is equivalent to subject, java.util.observer, when you want to use simple inheritance. However, in order to better scalability and more clear logic, the ThreadPool class has no inheritance of the OBSERVABLE class, but uses your own implementation. (5) RUNIT method Public Synchronized Void Runit (ThreadpoolRunnable Torun { THIS.torun = Torun; Shouldrun = true; THIS.NOTIFY (); } This method is mainly to run a specified task. The specific tasks are packaged in the ThreadpoolRunnable interface, which should pay attention to the following: Ø This method is only called once for each thread Ø Calling this method is not immediately running ThreadPoolRunnable specified tasks, but notifying the controlrunnable "to perform tasks". The specific task is performed in the RUN method below. (6) RUN method Public void run () { Try { While (true) { Try { Synchronized (this) { // When you don't run, wait IF (! ShouldRun &&! shopterminate) { THIS.WAIT (); } } //stop IF (shopterminate) { IF (threadpool.log.Indebugebund ()) Threadpool.log.debug ("terminate"); Break; } Try { // Initialization thread data, only once IF (nothdata) { IF Torun! = NULL) { Object thdata [] = torun.getinitdata (); T.SETTHREADDATA (P, THDATA); } NothData = FALSE; } // Perform actions IF (shoprun) { // Run the ThreadRunnalbe interface IF Torun! = NULL) { Torun.Runit (T.GetThreadData (P)); // ControlRunnable also provides opportunities for general Runnable interface participation } else if (torunRunnable! = null) { TorunRunnable.run (); } else { IF (threadpool.log.Indebugebund ()) Threadpool.log.debug ("NO TORUN ??? "); } } } catch (throwable t) { // Proactive error occurred, remove thread from the pool Shouldterminate = true; Shouldrun = false; P.NotifythReadenD (this); } finally { // Run the end recycle thread IF (shoprun) { Shouldrun = false; P. ReturnController (this); } } IF (shopterminate) { Break; } } catch (InterruptedException IE) { // You may happen when Wait (although this exception is unlikely) p.log.ERROR ("Unexpected Exception", IE; } } } finally { // Remove thread from the pool when an error occurs during the thread pool stop or thread operation P.Removethread (thread.currentthread ()); } } Combined with the RUNIT method, the RUN method can be easily understood. 4. Org.apache.tomcat.util.threads.threadpoollistener As we mentioned earlier, the OBServer mode of the OBSERVER mode is defined by the interface, which defines two methods: // Method when thread is created Public void threadstart (ThreadPool TP, Thread T); // Method for executing when thread is stopped Public void threadEND (ThreadPool TP, Thread T); The detailed use of the interface can refer to the OBServer mode mentioned above. 5. Org.apache.tomcat.util.Threads.Threadwithattributes Threadwithattributes is a special thread that is used to store properties and data of other threads, and this class provides a function similar to ThreadLocal, but is higher than Threadlocal efficiency. (1) Constructor Threadwithattributes Public Threadwithattributes (Object Control, Runnable R) { Super (r); THIS.CONTROL = Control; } Construct an instance with Control (ThreadPool) and R (Controlrunnable) (see ControlRunnable constructor) (2) Setnote method Public Final Void SetNote (Object Control, Int ID, Object Value) { IF (this.Control! = Control) Return; Notes [ID] = Value; } Ø Construct a new Threadwithattributes object with ControlRunnable to avoid the competition for thread utility Ø Set the thread attribute according to Control, you can block untrusted code operation thread properties via Control. There is no longer listed for other methods of handling thread attributes. (3) Java's Threadlocal Java.lang.ThreadLocal is a "thread local variable" that appears in Java1.2, which provides a copy of a single thread partial variable value for each thread using it. Each thread can only see the value associated with you, instead of other threads may be in use or modify their own copy. "Thread local variable" is a good way to simplify multi-threaded programming, but a pity that most developers may not understand it. Specific information can be referenced: http://www-900.ibm.com/developerWorks/cn/java/j-threads/index3.shtml 6. Org.apache.tomcat.util.threads.threadPoolRunnable As we mentioned before, if you want to embed your code inside the thread pool, you must implement the interface. Specifically, you can refer to the controlrunnable RUN method. This interface defines the following two methods: (1) GetinitData method Public object [] getinitdata (); The initialization data required to run the object is obtained, and the same type of data should be returned to all threads in the pool, otherwise the processing mechanism will become more complicated. (2) RUNIT method Public void Runit (Object Thdata []); The embedded code will be embodied in this method, and we will see later that the TCP Connection is processed here. At this point, Tomcat ThreadPool is introduced, even if the Tomcat Threadpool has always grasped the following: Ø Tomcat ThreadPool provides only the management and maintenance of threads Ø The operation performed by the pool has external components to implement Ø From the design of the pool, you can see the traces of the component (COP) programming two. ThreadPool Application in Treatment TCP Connection In the next content we will demonstrate how Tomat monitors the HTTP connection at the specified port and use ThreadPool to generate a thread processing acceptance request. 1. Org.apache.tomcat.util.net.pooltcpendpoint The class pooltcpendpoint is mainly used to handle the HTTP connection, the processing method is to handle the original socket, let's take a few important methods: (1) InitEndPoint method For this method, now we can temporarily consider too much, just know that it is enough to initialize Serversocket. Public void initendpoint () throws oException, instantiationException { Try { // Create a Serversocket factory IF (factory == NULL) Factory = serversocketFactory.getDefault (); // Create a ServerSocket, will be used to listen in the specified port (8080) IF (serversocket == null) { Try { IF (INET == NULL) { Serversocket = Factory.createsocket (port, backlog); } else { Serversocket = Factory.createsocket (port, backlog, inet); } } catch (bindexception be) { Throw new bindexception (be.getMessage () ":" port); } } // Set the timeout limit time of the connection IF (ServerTimeout> = 0) Serversocket.setSotimeout; ServerTimeout; } catch (ioException ex) { Throw EX; } catch (instantiationexception ex1) { Throw EX1; } / / Guaranteed initialization Initialized = True; } (2) STARTENDPOINT method This method will be called when TOCMAT is started, and the thread pool is started and the monitoring thread is generated. Public void startndpoint () throws oException, instantiationException { IF (! Initialized) { initendpoint (); } // TP is the ThreadPool object that the external component passes, here Tomcat launches the thread pool IF (ISPOOL) { Tp.start (); } Running = true; / / Generate a working thread monitor HTTP connection IF (ISPOOL) { Listener = New TCPWORKERTHREAD (THIS); TP.Runit (Listener); } else { Log. Error ("XXX Error - NEED POOL!"); } } Here, you will describe how the working thread monitors HTTP connection: 2. Org.apache.tomcat.util.net.tcpWorkeRThread This class is the internal class of pooltcpendpoint, which implements the ThreadPoolRunnable interface to perform HTTP connection listening and request processing. (Class TCPWORKERTHREAD IMPLEMENTS ThreadpoolRunnable) (1) Constructor TCPWORKERTHREAD The main purpose of this method is to generate an instance through the pooltcpendpoint object, and generate a certain number of TCPConnection objects in the cache. Public TCPWORKERTHREAD (pooltcpendpoint endpoint) { THIS.Endpoint = endpoint; IF (usepool) { // Cache Initialization SimplePool is a cache object, you can ignore its implementation details ConnectionCache = New SimplePool (endpoint.getmaxthreads ()); For (int i = 0; i ConnectionCache.put (New TcpConnection ()); } } } Our purpose is to clearly understand the monitoring and processing of HTTP, and it is not more important for other details. (2) GetinitData method As mentioned earlier in the description of this method, do you still remember? This method is mainly to obtain initialization data of the thread. Public object [] getinitdata () { IF (usepool) { Return endpoint.getConnectionHandler (). init (); } else { Object obj [] = new object [2]; // Second parameter Store HTTP request processor (you can not consider details first) Obj [1] = endpoint.getConnectionHandler (). init (); // The first parameter stores TCPConnection objects Obj [0] = new tcpConnection (); returnobj; } } Regarding the second parameters, it is actually initialized the HTTP request processor and other information, you can not be detailed. As long as you understand that this method is to return the thread to initialize the data. (3) RUNIT method As we said, the code embedded in the thread pool should be written in this method, this method is the core of HTTP listening, we see specific implementation: Public void Runit (Object Perthrdata []) { Endpoint.IsRunning ()) { Socket S = NULL; / / Listening to the client connection at the specified port (8080) Try { s = endpoint.acceptsocket (); } finally { // Continue to start the next thread after the connection is accepted Endpoint.IsRunning ()) { Endpoint.tp.runit (this); } } IF (NULL! = s) { Try { IF (endpoint.getserversocketFactory ()! = null) { // The client is shaking hands with the server, mainly for SSI connection (ie https) endpoint.getserversocketFactory (). Handshake (s); } } catch (throwable t) { PoolTcpendPoint.log.debug ("Handshake Failed", T); Try { s.close (); } catch (ioexception e) { } Return; } TcpConnection Con = NULL; Try { IF (usepool) { // Take a TCPConnection object from the cache ConnectionCache.Get (); IF (con == null) { CON = New TcpConnection (); } } else { // If you do not use a cache from initialization data to take a TCPConnection object Con = (tcpConnection) Perthrdata [0]; Perthrdata = (Object []) Perthrdata [1]; } // Set the TCPConnection object Con.sendpoint (endpoint); Con.setsocket (s); Endpoint.setsocketoptions (s); // Transfer TCPConnection and the initialization data required to HTTP processor processing // The original Socket stream is subjected to the REQUEST object transmission in the Process processing. / / Call to the container Endpoint.getConnectionHandler (). ProcessConnection (Con, Perthrdata); } catch (socketexception se) { Try { s.close (); } catch (ioexception e) {} } catch (throwable t) { Try { s.close (); } catch (ioexception e) {} } finally { IF (con! = null) { C.Recycle (); IF (usepool) { ConnectionCache.Put (con); } } } } } } Please take a closer and repeated look at the comments above shadows. Through the above, we see the work threads as follows: Ø Start the thread pool (the thread pool is started to generate a specified number of threads and monitoring threads) Ø If you use buffer processing, you will preriminate the specified number of TCPCONNECTION objects. Ø Monitor HTTP connections in the specified port (default is 8080) Ø Start a thread to continue listening to a connection when the received connection Ø Generate TCPConnection objects with the received connection, that is, Tomcat's processing of HTTP is based on TCPConnection object. Ø Turn the generated TCPConnection object to HTTP Process for Socket analysis, and finally generate the Request object It should be noted that Tomcat is not listening to the port with the specified number of threads, but when a listener is complete, start the next listening thread.