Probe into thread pool customization

Source: Internet
Author: User
Tags keep alive

Tag: control line directly supports ADF to prevent hex object SIM exception

Background

? I am in the company although is the mobile payment field of the company. But the business I do is similar to the management system, so when I first wrote the code, I didn't take into account the amount of data. Starting with a statistics page, the data that is about to be counted is divided into more than 10 dimensions, and then each dimension needs to consider about 10 aspects. That is, the statistics page gently click on a query button, to make about 100 times the database query. When the initial data volume is small, the query is also available and the page does not time out. To the back of the data volume is increasing, the largest table data volume has more than 100 million. This time the sad thing happened--- page click Query directly not responding .....

Scenario Considerations

? In fact, I thought of two kinds of solutions at that time:

  1. Optimization of the business implementation of logic, in fact, when querying a table of multiple dimensions of the query can pass a dimension list in. After the results are detected, the background is in the grouping calculation.
  2. With multi-threading, one thread executes on each dimension. In fact, the number of queries per thread is around 10 times, the total time can be almost 10 times times shorter.

? Of course, at the time I knew the best solution was to mix 1 and 2. But at the time the implementation of 1 had the following problems, and ultimately I decided to choose Scenario 2:

  1. Because each dimension involves more than one table, different tables belong to different modules. If a table's query criteria do not support the dimension list, then need to ask for the corresponding module development ... (What year and month can finish)
  2. The change in scenario 1 involves a lot of code changes, and it is not good to encapsulate each thread task, write out the code logic a bit around the background there are a large number of re-dimension statistics code. In short, it's not elegant .
Implementation considerations

? Now that you've finally chosen scenario 2, it's natural to consider selecting a thread pool. So what's the thread pool to choose? A single? Schedule must not want to pass directly. Cached? In fact, the current is feasible, because the current line of the dimension is more than 10. The cached thread pool, as long as the number of concurrent threads is not too large, and not too much pressure on the system to cause the system to collapse. But as the dimensions grow more and more as the business grows, the pressure on the system cannot be estimated if the subsequent dimensions increase to 20 or even 30.

? After thinking, I finally decided to choose the fix thread pool, and the thread pool would be cured to a size of 10. But this time I think, in fact, the number of pages a day query is not much. You may click on a query every morning, and you may not be able to query later. Then there are two kinds of egg-sore choices:

  1. Initialize the thread pool directly inside the method of the query
  2. Initializing the thread pool in the properties of a class

? The 1th scenario, each query to reinitialize the thread pool, causing a lot of resource consumption. If successive queries are repeated several times, and are not later than the previous faster, it is possible that the constant destruction of the thread pool creates the resulting slowdown. Finally I chose the 2nd option, of course, I did not choose a hungry man mode direct initialization, but chose the lazy mode in the method to initialize the thread pool, and through the lock is guaranteed to initialize only once.

Idea try

? If you think my customization is over here, you too young too naive. I do not seek to be feasible, only the pursuit of perfection ~

At this time I was thinking, in fact, according to the user's operating habits, Statistics page Query button, or just a few hours off, or it may be a whim, continuous query for a few days or the same day multiple dimensions of the query several times. And as we all know, the fix thread pool cures the size of the thread pool, and even if there are no tasks for several hours behind it, the number of threads in the initial size will still remain. Can it be possible to control the number of threads fix, and then destroy the core thread when it is idle? The answer is, of course, the key point is:Threadpoolexecutor's Allowcorethreadtimeout method

/*** Sets the policy governing whether core threads* Terminate if no tasks arrive within the keep-alive time, being* replaced if needed when new tasks arrive. When False, Core* Threads is never terminated due to lack of incoming* tasks. When True, the same keep-alive policy applying to* Non-core threads applies also to core threads. To avoid* Continual thread replacement, the keep-alive time must be* Greater than zero when setting <tt>true</tt>. This method* should in general being called before the pool is actively used.* @param value <tt>true</tt> If should time out, else <tt>false</tt>* @throws illegalargumentexception if value is <tt>true</tt>* and the current keep-alive time was not greater than zero.     *     * @since1.6     */     Public void Allowcorethreadtimeout(BooleanValue) {if(Value && KeepAliveTime <=0)Throw NewIllegalArgumentException ("Core threads must has nonzero keep alive times");    Allowcorethreadtimeout = value; }

? From the source code annotations, this method can support the keep-alive time setting of the thread pool and take effect on both the core thread and the non-core thread. Specifically why, after I analyze the line Cheng code will be said, now we just need to see the source (in Threadpoolexecutor's Gettask method ):

/*** Gets the next task for a worker, thread to run. the General* approach is similar to execute () in that worker threads trying* To get a task to run does so on the basis of prevailing state* accessed outside of locks. This could cause them to choose the* "wrong" action, such as trying to exit because no tasks* appear to being available, or entering a take when the pool was in* The process of being shut down. These potential problems is* countered by (1) rechecking pool State (in Workercanexit)* Before giving up, and (2) interrupting other workers upon* shutdown, so they can recheck state. All and user-based state* Changes (to allowcorethreadtimeout etc) is OK even when* performed asynchronously wrt gettask.     *     * @returnThe task     */RunnableGettask() { for(;;) {Try{intstate = Runstate;if(State > SHUTDOWN)return NULL; Runnable R;if(state = = SHUTDOWN)//help drain queueR = WorkQueue.Poll();Else if(Poolsize > Corepoolsize | | allowcorethreadtimeout) r = WorkQueue.Poll(KeepAliveTime, Timeunit.nanoseconds);ElseR = WorkQueue. Take();if(r! =NULL)returnRif(Workercanexit()) {if(Runstate >= SHUTDOWN)//Wake up others                        interruptidleworkers();return NULL; }//Else retry}Catch(Interruptedexception IE) {//on interruption, Re-check runstate}        }    }

? The key is that workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) the method represents an attempt to get a task from the wait queue and returns null if it exceeds keepalive time. If NULL is returned, the work thread is terminated.

? Ok these are something, after I see the source of the thread pool, I can clearly know why this parameter has this effect. So how did I test and verify my ideas before? It's actually very simple:

    1. I first refer to the thread pool by default DefaultThreadFactory defining my own threading factory, in order to get the properties inside the thread factory, ThreadGroup because ThreadGroup the class has a activeCount method that can get the number of active threads in the thread group.
classMythreadfactoryImplementsthreadfactory {Static FinalAtomicinteger Poolnumber =NewAtomicinteger (1);FinalThreadgroup Group;FinalAtomicinteger Threadnumber =NewAtomicinteger (1);FinalString Nameprefix;mythreadfactory() {SecurityManager s = System.getSecurityManager(); Group = (s! =NULL) ? S.Getthreadgroup(): Thread.CurrentThread().Getthreadgroup(); Nameprefix ="pool-"+ Poolnumber.getandincrement() +"-thread-"; } PublicThreadNewthread(Runnable R) {Thread T =NewThread (Group, R, Nameprefix + threadnumber.getandincrement(),0);if(T.Isdaemon()) T.Setdaemon(false);if(T.getpriority()! = Thread.norm_priority) T.setpriority(Thread.norm_priority);returnT }//I added the method in order to get the thread group         PublicThreadgroupGetthreadgroup() {return  This.Group; }    }
    1. Everything is ready, only owed the East wind, I only need to construct two different situations to verify my guess!
Mythreadfactory mythreadfactory =New mythreadfactory(); Threadpoolexecutor executor =NewThreadpoolexecutor (5,5,5, Timeunit.SECONDS,NewLinkedblockingqueue<runnable> (), mythreadfactory);//Executor.allowcorethreadtimeout (TRUE); for(inti =0; I <= -; i++) {executor.Submit(New myrunnable());} System. out.println(Mythreadfactory.Getthreadgroup().Activecount());//6Thread.Sleep(20000); System. out.println("After destroy, active thread count:"+ mythreadfactory.Getthreadgroup().Activecount());//6/1Executor.shutdown();

? Results of the operation:

  1. If you don't perform executor.allowCoreThreadTimeOut(true); two activecount, the result is 6.
  2. If executor.allowCoreThreadTimeOut(true); the result of executing the first activecount is 6, the result of the second activecount is 1
Final implementation

? Well, finally to the end of the custom implementation. My code is implemented as follows (class for spring-managed classes, the final thread pool shutdown at Predestroy):

    Private volatileThreadpoolexecutor searchexecutors;Private FinalObject lock =NewObject ();/*** Initialize the thread pool and start without initialization to avoid wasting system resources     */    Private void Initexecutor() {if(Searchexecutors! =NULL) {return; }synchronized(lock) {if(Searchexecutors = =NULL) {//Set a fixed size of 10, core thread if more than 10 minutes idle can also be destroyed by the thread poolThreadpoolexecutor Tempexecutor =NewThreadpoolexecutor (Ten,Ten,Ten, Timeunit.MINUTES,NewLinkedblockingqueue<runnable> (), executors.defaultthreadfactory()); Tempexecutor.Allowcorethreadtimeout(true); This.searchexecutors= Tempexecutor; }        }    }@PreDestroy     Public void Destroy() {if(Searchexecutors! =NULL) {searchexecutors.shutdown(); }    }

I'll say two here.

  1. This initialization method uses a Double-check-lock approach to ensure that multithreaded concurrency gets to the same thread pool instance
  2. Notice the use of a tempexecutor before setting the property searchexecutors. This is also an issue that prevents the Threadpoolexecutor object from being initialized, but the allowcorethreadtimeout has not yet been executed. (The object's premature escape causes the property to not match the expected).
Summarize

? Through this thread pool customization, found that in fact there is no technical content of the work, if you want to go down or there will be a lot of things to study deeply. And do the software in fact, like doing art, think more about different implementations may, as far as possible to choose the most perfect solution.

Probe into thread pool customization

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.