“This is the 27th day of my participation in the First Challenge 2022. For details: First Challenge 2022”
1. The introduction
Do not use Executors to create a thread pool. Java provides such a create class. * * * can’t use the Executors to create a thread pool during the development process?
2. Java provides Executors conjecture
Executors in Java is a class act as a tool, the Executor, the ExecutorService, ScheduledExecutorService, ThreadFactory semantic service. To enable users to better use different thread pools used in different businesses. Provide a unified thread pool factory to create. Such as:
-
Create a fixed size thread to use
Executors.newFixedThreadPool(int nThreads) Copy the code
This is made clear at creation time, which is to create a fixed size thread pool, so the number of threads is the parameter nThreads passed in
-
Create a single thread pool
Executors.newSingleThreadExecutor() Copy the code
This creates it without even taking arguments
So Java provides Executors for creating various thread pools to provide convenience, consistent with semantics. If that’s the case why is it not recommended? Isn’t that a contradiction
3. Why not use Executors to create a thread pool
Why not use Executors to create a thread pool we source code and examples to analyze. * * * Create a thread pool by following the following figure: * Create a thread pool by following the following figure: * Create a thread pool by following the following figure:
-
Set the fixed thread pool size
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } Copy the code
-
Set the thread pool size and customize the implementation ThreadFactory
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); } Copy the code
As you can see from the code, the difference between the two is whether ThreadFactory is implemented custom. It’s all about creating ThreadPoolExecutor.
3.1 Pros and cons of Creating ThreadPoolExecutor versus Executors
The advantages of creating thread pools in methods 1 and 2 over using ThreadPoolExecutor directly are simplicity and semantic clarity.
However, in method 1, the user cannot control the name of the thread pool and the length of the queue. The queue uses an unbounded queue. In method 2, the user can customize the name of the thread pool but should pay more attention to the queue than the name of the thread pool. Method 1 has the following advantages over Method 2: You cannot control the length of the queue. Executors are not recommended for this reason.
The allowed queue length is integer.max_value
Use code to demonstrate what can happen if you keep creating:
/ * * *@author mxsm
* @date 2022/2/9 22:01
* @Since 1.0.0
*
* -Xms5m
* -Xmx5m
*/
public class Phenomena1 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(1);
for(;;) { executorService.submit(newWork()); System.out.println(System.currentTimeMillis()); }}static class Work implements Runnable{
private StringBuilder builder = new StringBuilder();
public Work(a) {
for(int i = 0; i < 10000000; ++i){
builder.append(i);
}
System.out.println(builder.toString().getBytes(StandardCharsets.UTF_8).length/1024);
}
@Override
public void run(a) {
try {
System.out.println(System.currentTimeMillis());
TimeUnit.MINUTES.sleep(10);
} catch(InterruptedException e) { e.printStackTrace(); }}}}Copy the code
Running results:
Tips: Turn memory down
In the case of LinkedBlockingQueue, this will result in a huge backlog of requests and may result in OOM
3.2 Traceability of thread execution problems
When an error occurs in the thread pool execution, it is necessary to trace the error stack if you create a thread as follows:
public class Phenomena1 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(1);
ExecutorService executorService1 = Executors.newFixedThreadPool(2);
executorService.submit(new Runnable() {
@Override
public void run(a) {}}); executorService1.submit(new Runnable() {
@Override
public void run(a) {}}); }}Copy the code
Run the program and view the thread pool with a Java command:
jsp
jstack -l <pid>
Copy the code
Let’s look at threads
It is not clear from the above figure which thread pool these two threads belong to.
So many people don’t set up custom ThreadFactory when using Executors, which is why it’s not recommended to use Executors.
4. Do not use the Executors to create a thread pool at all
If you can solve the above two problems, you can use the custom ThreadFactory as a parameter to create a thread pool. Another is the ability to anticipate the number of tasks and not run out of resources because of an infinite number of submitted tasks.
5. To summarize
- It is not recommended to use Executors to create a thread pool for two reasons. First, if you use Executors, use the default case. Failure to customize the thread name is not conducive to troubleshooting. The second and most important reason is that the queue length of the thread pool is too long. In this case, tasks may be continuously added to the queue. Finally, the memory resources of the server will be exhausted before the queue goes online, resulting in OOM
- By creating a thread pool directly using ThreadPoolExecutor, the setup is relatively complex but much more flexible. Create the thread pool by following the Executors custom builtin the dev / * and add parameters to avoid the aforementioned problems if the semantics are the same
- Executors can also be used to create, but consider different scenarios.
I am ant back elephant, the article is helpful to you like to pay attention to me, the article has incorrect place please be corrected to leave a comment ~ thank you!