In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article introduces you how to deeply interpret the java thread pool design idea and source code implementation, the content is very detailed, interested friends can refer to, hope to be helpful to you.
Preface
Thread pooling is a very important tool. If you want to be a good engineer, you still need to master this knowledge. Many online problems are caused by poor use of thread pooling. Even if you want to make a living, you should know that this is basically a necessary question for the interview, and it is easy for the interviewer to capture the interviewee's technical level from the interviewee's answers.
Overview
Let's start with some nonsense. The following figure shows the inheritance structure of several related classes in the java thread pool:
Let's talk briefly about this inheritance structure. Executor is at the top level and is the simplest, defined by an execute (Runnable runnable) interface method.
ExecutorService is also an interface, and a lot of interface methods have been added to the Executor interface, so generally speaking we will use this interface.
Then the next layer is AbstractExecutorService, which we know from the name, this is an abstract class, and here we implement some very useful methods for direct use by subclasses, which we'll talk about in more detail later.
Then we move on to our focus section, the ThreadPoolExecutor class, which provides a very rich set of functionality about thread pooling.
In addition, we cover these classes in the following figure:
The Executors class, which is also in the parallel package, has the letter s in its name. We guessed that this is a utility class, and the methods in it are all static methods, such as the following methods we most commonly use to generate instances of ThreadPoolExecutor:
Public static ExecutorService newCachedThreadPool () {return new ThreadPoolExecutor (0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue ()) } public static ExecutorService newFixedThreadPool (int nThreads) {return new ThreadPoolExecutor (nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue ());}
In addition, because the thread pool supports getting the results of thread execution, the Future interface is introduced, from which RunnableFuture inherits, and the most important thing we need to care about is its implementation class FutureTask. At this point, remember this concept, in the process of using the thread pool, we submit tasks to the thread pool (task). Anyone who has used the thread pool knows that every task we submit implements the Runnable interface, in fact, the Runnable task is packaged as FutureTask before submitting to the thread pool. This makes it easier for readers to remember the class name FutureTask: it is first a Task and then has the semantics of the Future interface, that is, the results that can be executed in the future (Future).
Of course, BlockingQueue in the thread pool is also a very important concept. If the number of threads reaches corePoolSize, each of our tasks will be submitted to the waiting queue, waiting for threads in the thread pool to fetch the task and execute it. The BlockingQueue here usually uses its implementation classes LinkedBlockingQueue, ArrayBlockingQueue and SynchronousQueue, each of which has different characteristics, which will be analyzed slowly after the usage scenario. Readers who want to learn more about each BlockingQueue can refer to my previous article that analyzed the various implementation classes of BlockingQueue in detail.
To put things in perspective: in addition to the classes mentioned above, there is another very important class, the timing task implementation class ScheduledThreadPoolExecutor, which inherits from ThreadPoolExecutor, which is the focus of this article, and is used to implement timing execution. However, this article will not introduce its implementation, I believe readers can easily understand its source code after reading this article.
Above is the knowledge that this article wants to introduce, nonsense does not say much, begin to enter the text.
Executor interface / * * @ since 1.5 * @ author Doug Lea * / public interface Executor {void execute (Runnable command);}
We can see that the Executor interface is very simple, just a void execute (Runnable command) method that represents the submission of a task. In order to make you understand the whole design of java thread pool, I will say a few more things about it according to the design idea of Doug Lea.
We often start a thread like this:
New Thread (new Runnable () {/ / do something}) .start ()
After using the thread pool Executor, you can use it as follows:
Executor executor = anExecutor;executor.execute (new RunnableTask1 ()); executor.execute (new RunnableTask2 ())
If we want the thread pool to perform each task synchronously, we can implement this interface like this:
Class DirectExecutor implements Executor {public void execute (Runnable r) {r.run (); / / new Thread (r) .start () is not used here, which means that no new thread is started. }}
We hope that after each task is submitted, we will directly start a new thread to execute the task, which we can do as follows:
Class ThreadPerTaskExecutor implements Executor {public void execute (Runnable r) {new Thread (r) .start (); / / each task is executed with a new thread}}
Let's take a look at how to combine two Executor to use. The following implementation adds all the tasks to a queue, then takes the tasks from the queue and hands them to the real executor for execution. Here, synchronized is used for concurrency control:
Class SerialExecutor implements Executor {/ / Task queue final Queue tasks = new ArrayDeque (); / / this is the real executor final Executor executor; / / when the currently executing task Runnable active; / / initializes, specify the executor SerialExecutor (Executor executor) {this.executor = executor } / / add tasks to thread pool: add tasks to the task queue, and scheduleNext triggers the executor to fetch tasks public synchronized void execute (final Runnable r) {tasks.offer (new Runnable ()) {public void run () {try {r.run () } finally {scheduleNext ();}); if (active = = null) {scheduleNext () }} protected synchronized void scheduleNext () {if ((active = tasks.poll ())! = null) {/ / specific execution is transferred to the real actuator executor executor.execute (active);}
Of course, the Executor interface only has the function of submitting tasks, which is too simple. We want richer functions, such as we want to know the execution result, how many threads are alive in the current thread pool, how many tasks have been completed, and so on. These are the shortcomings of this interface. Next we will introduce the ExecutorService interface, which inherits from the Executor interface, which provides rich functions and is the interface we use most often.
ExecutorService
Generally, when we define a thread pool, we often use this interface:
ExecutorService executor = Executors.newFixedThreadPool (args...); ExecutorService executor = Executors.newCachedThreadPool (args...)
Because the series of methods defined in this interface can already meet our needs in most cases.
So let's take a brief look at what methods are available in this interface:
Public interface ExecutorService extends Executor {/ / closes the thread pool, the submitted task continues to execute, does not accept the continued submission of new tasks void shutdown (); / / closes the thread pool, attempts to stop all tasks in progress, and does not accept the continued submission of new tasks / / compared with the previous method, it adds the word "now", the difference is that it will stop the currently ongoing task List shutdownNow () / / whether the thread pool has closed boolean isShutdown (); / / if all tasks are finished after calling the shutdown () or shutdownNow () method, return true / / this method must be called after the shutdown or shutdownNow method is called before it returns true boolean isTerminated () / wait for all tasks to complete and set the timeout / / as we understand it, in practical application, first call shutdown or shutdownNow, / / and then call this method to wait for all threads to actually complete. The return value means that there is no timeout boolean awaitTermination (long timeout, TimeUnit unit) throws InterruptedException; / / to submit a Callable task Future submit (Callable task). / / submit a Runnable task, the second parameter will be put in Future as the return value, / / because the run method of Runnable itself does not return anything Future submit (Runnable task, T result); / / submit a Runnable task Future submit (Runnable task); / / perform all tasks and return a list List invokeAll of type Future (Collection)
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.