Reproduced Java thread Pool Framework source code Analysis

Source: Internet
Author: User
Tags throwable

Reprinted from Http://www.linuxidc.com/Linux/2014-11/108791.htm

Related Classes Executor,executors,abstractexecutorservice,executorservice

Executor: The top-level interface of the entire thread pool performer framework. Defines an Execute method, which is the core method of the entire thread-performer framework.

Public interface Executor {

void execute (Runnable command);
}

Executorservice: This is an interface which inherits from executor, defines methods such as Shutdown,shutdownnow,awaittermination,submit,invokeall.

Abstractexecutorservice: Implements the method of Submit,invokeall in the Executorservice interface.

Public future<?> Submit (Runnable Task) {
if (task = = null) throw new NullPointerException ();
runnablefuture<void> ftask = newtaskfor (task, NULL);
Execute (ftask);
return ftask;
}

Public <T> future<t> Submit (Runnable task, T result) {
if (task = = null) throw new NullPointerException ();
runnablefuture<t> ftask = newtaskfor (task, result);
Execute (ftask);
return ftask;
}


Public <T> future<t> Submit (callable<t> Task) {
if (task = = null) throw new NullPointerException ();
runnablefuture<t> ftask = newtaskfor (Task);
Execute (ftask);
return ftask;
}

Here, all of the tasks submitted by the Submit method ultimately call the Execute method, execute is the method defined in interface executor, Abstractexecutorservice does not implement it,

Subclasses are required to implement this method, and Threadpoolexecutor inherits the Abstractexecutorservice, which implements the Execute method. Scheduledthreadpoolexecutor inherits from

Threadpoolexecutor, and overrides the Execute method of the Threadpoolexecutor. This method is the core logic of the thread execution box holder, and different thread pool performers have different implementation logic.

The function of Abstractexecutorservice is relatively simple, and the Submit,invokeall method of different parameters is realized.

Threadpoolexecutor thread pool performer: It has a core member variable:

Private final hashset<worker> workers = new hashset<worker> ();

Workers can be seen as the pool of threads used to run tasks in Threadpoolexecutor.

A worker is a class that encapsulates a thread object and implements the Runnable interface. The wrapper thread is easy to understand because it uses thread to run the Runnable task submitted by the Execute method, but why does it inherit the Runnable interface?

Here is the worker source code that excludes some of the codes:

Private Final Class Worker
Extends Abstractqueuedsynchronizer
Implements Runnable
{
Final thread thread;

Runnable Firsttask;

Worker (Runnable firsttask) {
SetState (-1);
This.firsttask = Firsttask;
This.thread = Getthreadfactory (). Newthread (this);
}

public void Run () {
Runworker (this);
}


}

Worker is an inner class of threadpoolexecutor, the worker itself implements the Runnable interface, encapsulates a thread object, and finally acquires a Runnable object in the constructor method. This object is the target task submitted by Threadpoolexecutor via execute.

Trace Runworker (This) method:

final void Runworker (Worker w) {
Thread wt = Thread.CurrentThread ();
Runnable task = W.firsttask;
W.firsttask = null;
W.unlock ();
Boolean completedabruptly = true;
try {
while (task! = NULL | | (Task = Gettask ()) = null) {
W.lock ();

if (Runstateatleast (Ctl.get (), STOP) | |
(Thread.interrupted () &&
Runstateatleast (Ctl.get (), STOP)) &&
!wt.isinterrupted ())
Wt.interrupt ();
try {
BeforeExecute (WT, Task);
Throwable thrown = null;
try {
Task.run ();//The Run method of the target task is called directly here, and it is not passed to the thread object.
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error (x);
} finally {
AfterExecute (task, thrown);
}
} finally {
task = null;
w.completedtasks++;
W.unlock ();
}
}
completedabruptly = false;
} finally {
Processworkerexit (w, completedabruptly);
}
}

Look back to see how the worker is constructed:

Worker (Runnable firsttask) {
SetState (-1);
This.firsttask = Firsttask;
This.thread = Getthreadfactory (). Newthread (this);
}

It passes itself to the member variable thread. The step that the target task is executed may be: The worker's member variable thread starts and calls the worker's Run method, and the worker's Run method passes itself to the run method of Runworker,runworker in the call to the target execution object.

So when did the thread get executed?

Here's a look at one of the other methods in Threadpoolexecutor:

Private Boolean Addworker (Runnable Firsttask, Boolean core) {
......
try {
Final Reentrantlock mainlock = This.mainlock;
w = new Worker (firsttask);
Final Thread t = w.thread;//Here Initializes a worker object W, and in the member variable of W the Thread is paid T
if (t! = null) {
Mainlock.lock ();
try {
int c = Ctl.get ();
int rs = runstateof (c);

if (Rs < SHUTDOWN | |
(rs = = SHUTDOWN && Firsttask = = null)) {
if (T.isalive ())
throw new Illegalthreadstateexception ();
Workers.add (w);
int s = workers.size ();
if (S > Largestpoolsize)
Largestpoolsize = s;
Workeradded = true;
}
} finally {
Mainlock.unlock ();
}
if (workeradded) {
T.start ();//Call the Start method of T here.
Workerstarted = true;
}
}
} finally {
if (! workerstarted)
Addworkerfailed (w);
}
return workerstarted;
}

Why is it so designed here, I think the main thing is that the worker not only encapsulates a thread, but also encapsulates the target task, Addworker can do some related operations before running the target task after encapsulation.

Here is just a description of the threadpoolexecutor thread pool, how the thread pool is maintained, and a few key parameters are described below.

private volatile int corepoolsize;
private volatile int maximumpoolsize;
Private final blockingqueue<runnable> WorkQueue;

These three are Threadpoolexecutor member variables, where workqueue is not related to the county pool. Workqueue is a thread-safe blocking queue.

Corepoolsize is the core size of the thread pool, and maximumpoolsize is the maximum size of the thread pool.

When a new task is submitted, if the thread is running in Threadpoolexecutor and the number of threads is less than corepoolsize, then a new thread is created. If the number of threads currently running is greater than corepoolsize, it is placed in the cache queue Workqueue. If the buffer queue is full, continue creating the thread until the number of threads reaches Maximumpoolsize

public void Execute (Runnable command) {
if (command = = null)
throw new NullPointerException ();

       //Judging if the number of threads currently running is less than corepoolsize, add a new thread (Addworker adds a new thread, described above), and the method returns directly.
        int c = Ctl.get ();
        if (Workercountof (c) < corepoolsize) {
            IF (Addworker (command, True))
                return;
            C = ctl.get ();
       }


If the current number of threads running is greater than or equal to Corepoolsize, the new task is placed in the cache queue.
if (IsRunning (c) && workqueue.offer (command)) {
int recheck = Ctl.get ();
if (! isrunning (Recheck) && Remove (command))
Reject (command);
else if (workercountof (recheck) = = 0)
Addworker (null, FALSE);
}
else if (!addworker (command, FALSE))
The last buffer queue addition fails, and the thread continues to be added. If adding a new thread fails, the task is rejected.
Reject (command);

}

There are some other parameters:

Private volatile threadfactory threadfactory//thread's factory function.
Private volatile rejectedexecutionhandler the processing class for handler;//task rejection.
The private volatile long keepalivetime;//task is waiting for the.

Threadpoolexecutor has several constructor methods to initialize these parameters. The executors class simplifies these parameters to obtain a executorservice reference.

public static Executorservice newfixedthreadpool (int nthreads) {
return new Threadpoolexecutor (Nthreads, Nthreads,
0L, Timeunit.milliseconds,
New linkedblockingqueue<runnable> ());
}

      public static executorservice newfixedthreadpool (int nthreads, threadfactory threadfactory) {
        return new Threadpoolexecutor (Nthreads, Nthreads,
          &N Bsp                         0L, Timeunit.milliseconds,
& nbsp                          ,         &NB Sp New Linkedblockingqueue<runnable> (),
                    &NBSP ;                 threadfactory);
   }

    public static Executorservice Newcachedthreadpool () {
        return new Threadpoo Lexecutor 0, Integer.max_value,
                        &NB Sp             60L, Timeunit.seconds,
              &NBSP ;                       new synchronousqueue<runnable> ());
   }

    public static Executorservice Newcachedthreadpool (Threadfactory threadfactory) {
        return new Threadpoolexecutor (0, Integer.max_value,
              &NBS P                       60L, Timeunit.seconds,
    &NBSP ;                                 New SYNCHR Onousqueue<runnable> (),
                        &NBSP ;             threadfactory);
   }

The first two of these four methods have the same number of core threads and the maximum number of threads, and the number of threads that can be run is fixed, <=nthreads.  When the number of tasks is greater than nthreads, it is placed in the buffer queue. In the latter two methods, the number of threads is borderless, the number of core threads is 0, the maximum number of threads is the maximum value of an integer, and then destroyed if no task runs within 60 seconds of the thread. Each time a new task comes, a new thread is created or a previously created thread (a thread with no tasks running in 60 seconds). You may have doubts that since the number of core threads is 0, isn't all the tasks on the team? So now take a look at Synchronousqueue this team, you can look at the introduction http://www.linuxidc.com/Linux/2014-11/108792.htm here.

Look back at the source of the task submission method:

public void Execute (Runnable command) {
if (command = = null)
throw new NullPointerException ();
int c = Ctl.get ();
if (Workercountof (c) < corepoolsize) {
if (Addworker (command, True))
Return
c = Ctl.get ();
}
if (IsRunning (c) && workqueue.offer (command)) {//Here is a task in the queue, and if unsuccessful, the worker is added (encapsulates the thread object)
int recheck = Ctl.get ();
if (! isrunning (Recheck) && Remove (command))
Reject (command);
else if (workercountof (recheck) = = 0)
Addworker (null, FALSE);
}
else if (!addworker (command, FALSE))
Reject (command);
}

The above link mentions: Offer () returns immediately after placing an element in the queue, and if it happens that the element was taken away by another thread, the Offer method returns true to the offer and returns false.

Imagine that the first time you commit a task, the number of core threads is 0, there are no threads so there is no thread to fetch from Workqueue, so the Workqueue.offer command will return false, then it will go through Addworker ( command, FALSE) to create a new thread.

Reproduced Java thread Pool Framework source code Analysis

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.