Jetty Learning "four" threads

Source: Internet
Author: User
Tags current time int size terminates
1. Thread poolTwo thread pools, Excutorthreadpool and Queuedthreadpool, were implemented in Jetty 8. Where Excutorthreadpool is the encapsulation of the Java thread pool, and queuedthreadpool is the implementation of executor. Here's a look at the definition of these two thread pools.
/*------------------------------------------------------------
*//**
 * Jetty ThreadPool using Java 5 Threadpoolexecutor
 * This class wraps a {@link Executorservice} as a {@link ThreadPool} and
 * {@link LifeCycle} in Terfaces so it is used by the Jetty <code>org.eclipse.jetty.server.Server</code>
 * * Public
C Lass Executorthreadpool extends Abstractlifecycle implements ThreadPool, LifeCycle

public class Queuedthreadpool extends Abstractlifecycle implements Sizedthreadpool, Executor, dumpable

2, the realization of Queuedthreadpool 2.1. Properties
   Number of threads already started
    private final atomicinteger _threadsstarted = new Atomicinteger ();
    Number of idle threads
    Private final Atomicinteger _threadsidle = new Atomicinteger (); 
    private final Atomiclong _lastshrink = new Atomiclong ();
    Collection of all started threads
    Private final concurrentlinkedqueue<thread> _threads=new Concurrentlinkedqueue<thread > ();
    Shared variable
    Private Final Object _joinlock = new Object ();
    Blocking queue, which is used to store the job that needs to be executed
    private blockingqueue<runnable> _jobs;
    _name
    private String _name;
    Maximum idle time, which should be understood here as the maximum duration for the thread pool to have idle threads
    private int _maxidletimems=60000;
    Maximum number of threads
    private int _maxthreads=254;
    Maximum thread number
    private int _minthreads=8;
    Maximum queued
    private int _maxqueued=-1;
    Thread-priority
    private int _priority=thread.norm_priority;
    Whether it is a daemon thread
    private Boolean _daemon=false;
    Max stop time
    private int _maxstoptime=100;
    Private Boolean _detaileddump=false;

2.2. Constructor function
    /*-------------------------------------------------------------------*/
    /** Construct
     */Public
    Queuedthreadpool ()
    {
    	//Set thread name to start with QTP
        _name= "QTP" +super.hashcode ();
    }

    /*-------------------------------------------------------------------*/
    /** Construct
     */Public
    Queuedthreadpool (int maxthreads)
    {this
        ();
        Sets the maximum number of threads
        setmaxthreads (maxthreads);
    }

    /*-------------------------------------------------------------------*/
    /** Construct
     */Public
    Queuedthreadpool (blockingqueue<runnable> jobq)
    {this
        ();
        Set the blocking queue
        _JOBS=JOBQ;
        Clear the blocking queue
        _jobs.clear ();
    }

2.3. Start thread poolThe actual boot thread is through the Dostart () function.
    @Override
    protected void Dostart () throws Exception
    {
    	//Call parent Class Dostart ()
        super.dostart ();
        Setting _threadsstarted to 0 indicates that the thread is numbered
        _threadsstarted.set (0) starting with 0;

        If _jobs is empty, add a default queue for the thread pool.
        if (_jobs==null)
        {
        	//if _maxqueued is greater than 0, the Arrayblockingqueue is created and the size is _maxqueued
        	//If _maxqueued is less than or equal to 0, Blockingarrayqueue is created, Size is _minthreads, can grow to _minthreads
            _jobs=_maxqueued>0? New Arrayblockingqueue<runnable> (_maxQueued)
                : New blockingarrayqueue<runnable> (_minthreads,_minthreads);
        }

        Gets the thread number initial value
        int threads=_threadsstarted.get ();
        The number of startup threads is _minthreads, the default is 8 while
        (IsRunning () && threads<_minthreads)
        {
        	//start thread, numbered threads
            Startthread (threads);
            Threads=_threadsstarted.get ();
        }
    }

As you can see from the code above, 8 threads are started by default. Let's verify the following:
1) Open cmd and enter command Jconsole. See the following interface,

2) Select HelloWorld, then select the thread on the interface.


You can see that there are 8 threads that start with QTP, exactly the same as the default minimum number of threads mentioned above. As you can see, there are already two threads already in use, one selector, and one acceptor.
Then take a look at how Startthread () starts a thread in the current frame.
   /*------------------------------------------------------------*
    /private Boolean startthread (int threads)
    {
    	//Set the ID of the next thread to
        final int next=threads+1;
        Ensure that threads and _threadsstarted are consistent
        if (!_threadsstarted.compareandset (threads,next))
            return false;

        Boolean started=false;
        Try
        {
        	//threads Initialize thread
            thread=newthread (_runnable);
            Thread.setdaemon (_daemon);
            Thread.setpriority (_priority);
            Thread.setname (_name+ "-" +thread.getid ());
            Place the thread in the _threads
            _threads.add (thread);

            Thread start
            thread.start ();
            started=true;
        }
        Finally
        {
            if (!started)
            	//thread fails to start, then _threadsstarted-1
                _threadsstarted.decrementandget ();
        }
        return started;
    }

The simple thing to do is to first make sure that the thread number is correct, then update _threadsstarted, then start the thread and put the thread into _threads for unified management.
2.4. Perform TasksTask distribution, the main responsibility is to add the task to the waiting queue. Creates a new thread if the current number of threads does not meet the current task.
    /*------------------------------------------------------------*
    /public boolean dispatch (Runnable job)
    {
        if (isrunning ())
        {
        	//Get jobs Current number
            final int jobq = _jobs.size ();
            Gets the number of threads currently idle
            final int idle = Getidlethreads ();
            Job INSERT INTO _jobs
            if (_jobs.offer (Job))
            {
                //If we had no idle threads or the JOBQ is greater than the idle th Reads if
                (idle==0 | | jobq>idle)
                {
                	//If the threads number is less than _maxthreads, add a new thread
                    int threads=_ Threadsstarted.get ();
                    if (threads<_maxthreads)
                        startthread (threads);
                }
                return true;
            }
        }
        Log.debug ("dispatched {} to stopped {}", job,this);
        return false;
    }

and the actual execution of the task is in a defined thread, to see the contents of the thread,
    Private Runnable _runnable = new Runnable () {public void Run () {Boolean shrink=false
            ;
                try {//Get job Runnable job=_jobs.poll (); while (IsRunning ()) {//Job loop while (Job!=null && ISRU
                        Nning ()) {//Perform task runjob (job);
                    Job=_jobs.poll ();
                        }//Idle loop try {//free thread + 1

                        _threadsidle.incrementandget ();
                        	Idle loop while (IsRunning () && job==null) {
                                When the maximum idle event < 0 o'clock, check directly if there is a job task to perform if (_maxidletimems<=0)
                      Job=_jobs.take ();      Otherwise else {//maybe we sho
                                Uld shrink?
                                Final int size=_threadsstarted.get ();
                                If the current number of threads is greater than the minimum number of threads, it is possible that some of these threads will be terminated.
                                    if (size>_minthreads) {//The last time the thread was destroyed, the value will be changed when the threads are destroyed
                                    Long Last=_lastshrink.get ();
                                    Gets the current time long now=system.currenttimemillis (); Last is 0, or now-last is greater than maximum idle if (last==0 | | (now-last) >_maxidletimems) {//modify last, simultaneously modify the number of threads
                                        Meguro Shrink=_lastshrink.compareandset (Last,now) && _threadsstarted.compareanDSet (size,size-1);
                                    if (shrink) return;
                                }}//Get job, if no will wait _maxidletimems ms
                            Job=idlejobpoll ();
                        }}} finally {
                    _threadsidle.decrementandget ();
            }}} catch (Interruptedexception e) {Log.ignore (e);
            } catch (Exception e) {Log.warn (e);
                } finally {if (!shrink) _threadsstarted.decrementandget ();
            _threads.remove (Thread.CurrentThread ()); }
        }
    };

The workflow is still relatively clear, primarily to perform tasks, thread waits, and then threads to destroy, as well as updates for individual shared variables. In fact, the queue is constantly waiting to remove the job, execution. When there are idle threads in the thread pool, and this situation reaches a certain point (_maxidletimems), and the current number of threads exceeds the defined minimum number of threads, the redundant threads are terminated, and the number of threads is minimized (_minthreads). This is done to reduce the consumption of resources, because idle threads are required to keep looping, waiting for the job to come, and this consumes CPU time.
Looking at the threads that have been started, you can see that the status of the above 8 threads in addition to the selector and acceptor threads is runnable, the other threads are time_waiting, and the status of a thread is viewed as follows.
Sun.misc.Unsafe.park (Native Method)
Java.util.concurrent.locks.LockSupport.parkNanos (Unknown Source)
Java.util.concurrent.locks.abstractqueuedsynchronizer$conditionobject.awaitnanos (Unknown Source)
Org.eclipse.jetty.util.BlockingArrayQueue.poll (blockingarrayqueue.java:342)
Org.eclipse.jetty.util.thread.QueuedThreadPool.idleJobPoll (queuedthreadpool.java:526)
org.eclipse.jetty.util.thread.queuedthreadpool.access$600 (queuedthreadpool.java:44)
Org.eclipse.jetty.util.thread.queuedthreadpool$3.run (queuedthreadpool.java:572)
Java.lang.Thread.run (Unknown Source)

You can see that the thread hangs on the Idlejobpoll,
    Private Runnable Idlejobpoll () throws Interruptedexception
    {
        return _jobs.poll (_maxidletimems, timeunit.milliseconds);
    }

_maxidletimems = 60000, time is 1 minutes. So most of the time, the state of six threads is time_waiting.
3, the application of thread pool in jetty 3.1. Acceptor threadIn the Dostart () function in Abstractconnector, the acceptor thread is started.
    /*------------------------------------------------------------
    *
    /@Override protected void Dostart () Throws Exception
    {
		...
        Start Selector Thread
        synchronized (this)
        {
            _acceptorthreads = new thread[getacceptors ()];

            for (int i = 0; i < _acceptorthreads.length; i++)
		//based on the number of configured acceptor, start n threads
                if (!_threadpool.dispatch (new A Cceptor (i))
                    throw new IllegalStateException ("!accepting");
            if (_threadpool.islowonthreads ())
                Log.warn ("Insufficient threads configured for {}", this);
        }
		......
    }

And acceptor is the task to be submitted, the specific definition is as follows,
 Private class Acceptor implements Runnable {int _acceptor = 0;
        Acceptor (int id) {_acceptor = ID;
        	}/*------------------------------------------------------------*/public void run () {
            Gets the current thread, threads present = Thread.CurrentThread ();
            String name;
                    Locking synchronized (abstractconnector.this) {if (_acceptorthreads = = null)
                Return
                Set _acceptothreads _acceptor to current thread _acceptorthreads[_acceptor] = present;
                Get the name of the current thread name = _acceptorthreads[_acceptor].getname ();
            Update name Current.setname (name + "acceptor" + _acceptor + "" + abstractconnector.this);

            }//Get current priority int old_priority = Current.getpriority (); try {//Update priority CurreNt.setpriority (Old_priority-_acceptorpriorityoffset);
                        while (IsRunning () && getconnection () = null) {try {
                    Accept (_acceptor);
                    } catch (Eofexception e) {Log.ignore (e);
                    } catch (IOException e) {Log.ignore (e); } catch (Interruptedexception x) {//Connector H
                    As been stopped Log.ignore (x);
                    } catch (Throwable e) {Log.warn (e);
                }}} finally {current.setpriority (old_priority);

                Current.setname (name); SynchronizeD (abstractconnector.this) {if (_acceptorthreads! = null) _AC
                Ceptorthreads[_acceptor] = null;
 }
            }
        }
    }

You can see that one step here is to update the name of the thread, the rule is name + "acceptor" + _acceptor + "" + abstractconnector.this. So you can see in the screenshot above about 8 threads that another thread's name is qtp26994414-12 Acceptor0 selectchannelconnector@0.0.0.0:8080, just in accordance with this rule. It just shows that this thread is for accept. 3.2. Selector threadThe Dostart () function in Selectormanager has the following section of code,
			Use the dispatch function to distribute the thread, and get the return value of Boolean selecting = Dispatch (New Runnable () {public void run () {String name =
					Thread.CurrentThread (). GetName ();
					int priority = Thread.CurrentThread (). GetPriority ();
						try {selectset[] sets = _selectset;
						if (sets = = null) return;

						Get the i selector selectset set = Sets[id];
						Set name Thread.CurrentThread (). SetName (name + "Selector" + ID); if (Getselectorprioritydelta ()! = 0) Thread.CurrentThread (). SetPriority (Thread.CurrentThread (). GetPriorit
						Y () + Getselectorprioritydelta ());
						Log.debug ("starting {} on {}", Thread.CurrentThread (), this);
							Thread main content: Selector non-stop doselect () while (IsRunning ()) {try {set.doselect ();
							} catch (IOException e) {Log.ignore (e);
							} catch (Exception e) {Log.warn (e); }}} finally {Log.debug ("Stopped {} on {}", Thread.CurrentThread (), This);
						Thread.CurrentThread (). SetName (name);
					if (Getselectorprioritydelta ()! = 0) Thread.CurrentThread (). SetPriority (priority); }
				}

			});

It can be found that the naming rules for the Selector thread are name + "Selector" + ID, and the Selector thread name in the thread screenshot is qtp26994414-10 Selector0, exactly in line with this rule.
4, ShutdownthreadThe thread that needs to be called before the main thread terminates.
Defined as follows,
/*------------------------------------------------------------
*//**
 * Shutdownthread is a shutdown hook Thread implemented as 
 * Singleton that maintains a list of the lifecycle instances * that is
 registered with it and P Rovides ability to stop
 * These lifecycles upon shutdown of the Java Virtual machine 
 */Public
class Shutdownt Hread extends Thread

According to Javadoc, this thread provides the ability to stop each lifecycle before stopping the virtual machine.
    public static synchronized void Register (LifeCycle ... lifecycles)
    {
        _thread._lifecycles.addall ( Arrays.aslist (lifecycles));
        if (_thread._lifecycles.size () >0)
            _thread.hook ();
    }

Register the lifecycle that need attention, and these lifecycle need to be stopped before the virtual machine stops. The main thing here is the hook () function,
    Private synchronized void Hook ()
    {
        try
        {
            if (!_hooked)
                runtime.getruntime (). Addshutdownhook ( this);
            _hooked=true;
        }
        catch (Exception e)
        {
            log.ignore (e);
            Log.info ("Shutdown already commenced");
        }
    }

The hook calls Runtime.getruntime (). Addshutdownhook (this), adding its own thread to the hook of the main thread. This thread is called when the main thread terminates.
Here's a look at the main content of this thread,
    /*------------------------------------------------------------
    *
    /@Override public void Run ()
    {
        For (LifeCycle LifeCycle: _thread._lifecycles)
        {
            try
            {
                if (lifecycle.isstarted ())
                {
                    Lifecycle.stop ();
                    Log.debug ("Stopped {}", lifeCycle);
                }
                
                if (lifeCycle instanceof destroyable)
                {
                    ((destroyable) lifeCycle). Destroy ();
                    Log.debug ("Destroyed {}", lifeCycle);
                }
            }
            catch (Exception ex)
            {
                log.debug (ex);
            }
        }
    }

The code is very concise and clear, no explanation.
5. SummaryJetty itself implements a thread pool, as well as a mechanism for customizing thread recycling and threading pool expansion. This gives us a good example of how to complete a thread pool, as learning is still very good.

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.