This article looks at the basic usage of Java thread pools

directory

  • How Java thread pools are created
  • The instance
  • The example analysis
  • The results
  • supplement

How Java thread pools are created

Java provides the following methods for quickly creating a thread pool: Use the Executors class provided by the java.util.concurrent package to create a thread pool:

// Create a thread pool with a fixed length. The maximum number of concurrent threads can be controlled. public static ExecutorService newFixedThreadPool(int nThreads); // Create a single threaded thread pool that uses only one worker thread to execute tasks, ensuring that all tasks are executed in the specified order (FIFO, LIFO, priority). Public static ExecutorService newSingleThreadExecutor() // Create a fixed-length thread pool that supports scheduled and periodic task execution. Public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) If not, create a new thread. public static ExecutorService newCachedThreadPool()Copy the code

The above four thread pools almost cover most of the scenarios we encounter in ordinary coding. Their usage is very similar. In this article, we will focus on newSingleThreadExecutor and newFixedThreadPool. With Runnable/Callable/Future to explain the classic use of thread pool.

The instance

Let’s start with a piece of code:

public int doSomething()
{
    try
    {
        System.out.println("do something.");
        Thread.sleep(100);
    }
    catch (InterruptedException e)
    {
        e.printStackTrace();
    }

    return (new Random(1000)).nextInt();
}
Copy the code

To put it simply, we need 100ms to simulate a task and then return a random number. Based on this function, we know that the introduction of multithreading can complete the task concurrency, reduce the task time, improve the ability of the system to deal with the task.

Now consider a few questions:

  • 1. This task is to be executed in batches. One request can carry a large number of task identifiers and tasks to be processed
  • 2. Multiple requests can be processed simultaneously and concurrently;
  • 3. The requirements meet the actual carrying capacity of the system.

Modify the above requirements:

  • 1. In order to meet the requirements of batch execution, multi-thread modification scheme is introduced to create a specified number of thread pools according to the number of batch processing
  • 2, in order to meet each request can be processed concurrently, the introduction of single-threaded thread pool, each time the request is accepted, in the single-threaded thread pool to start the batch processing process
  • 3. In order to meet the actual carrying capacity of the system, the processing mode of creating a specified number of thread pools in the first step is changed to all requests of the system sharing thread resources

The example analysis

Instead of thinking, look directly at the code:

public class ThreadPool { public static ExecutorService es = Executors.newFixedThreadPool(20); public static void main(String[] args) throws InterruptedException { fixedThreadPool(5); Thread.sleep(2000); // Simulate the uncertainty of request initiation time. fixedThreadPool(50); fixedThreadPool(4); fixedThreadPool(6); System.out.println("submit task all");
        return;
    }

    private static void fixedThreadPool(int count)
    {
        long startTime = System.currentTimeMillis();
        Executors.newSingleThreadExecutor().execute(new Runnable()
        {
            @Override
            public void run() { Map<Integer, Future<Integer>> futures = new HashMap<>(); // Add 5 Callable tasks until the result is returnedfor (int i = 1; i <= count; i++)
                {
                    final long time = System.currentTimeMillis();
                    final int task = i;
                    Future<Integer> future = es.submit(new Callable<Integer>()
                    {
                        @Override
                        public Integer call()
                            throws Exception
                        {
                            try
                            {
                                Thread.sleep(100);
                            }
                            catch (InterruptedException e)
                            {
                                e.printStackTrace();
                            }

                            System.out.println("TaskFlag: " + count + ", Install MCS plugins " + task + " is working.");
                            return(new Random(1000)).nextInt(); }}); //future.get(); // This step blocks the thread's submission process, but does not block tasks in the thread pool. futures.put(task, future); }for (int i = 1; i <= count; i++)
                {

                    try
                    {

                        System.out.println("taskID: " + i + ", Res: " + futures.get(i).get());
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }

                System.out.println(count + "Install MCS plug-in task Submit completed! Time:"+ (System.currentTimeMillis() - startTime)); //es.shutdown(); //es.shutdown(); System.out.println("Executors. NewSingleThreadExecutor (). The execute: exit after shutdown! Time:"+ (System.currentTimeMillis() - startTime)); }}); }}Copy the code

The code is divided into three parts

  • 1. System thread pool definition, currently there are 20 length thread pool;
  • 2. Call fixedThreadPool() in main to simulate the request;
  • 3. The request content is defined in fixedThreadPool, that is, front-end requests are accepted and random number operations specified by users are performed each time.

What the code does

  • 1, create a single thread pool for asynchronous request processing, do not care about the execution result, directly return;
  • 2. In the requested single-thread thread pool, submit the batch operands to the system thread pool according to the batch operands entered by the user, wait for the operation result after submission, and print it.

The code analysis

1.

public static ExecutorService es = Executors.newFixedThreadPool(20);
Copy the code

The shared thread pool is created based on the system implementation capability. The value can be calculated based on the system carrying capacity, for example, the number of cpus.

2,

Executors.newSingleThreadExecutor().execute(new Runnable()
    {
        @Override
        public void run()
        {
	//do somethings
        }
    });
Copy the code

On each request, an anonymous class’s run method is executed directly through a single-threaded thread pool to perform the operation. Java The single-threaded thread pool provided in the java.util.concurrent package returns an ExecutorService object. Let’s look at the definition of ExecutorService:

ExecutorService
Executor

So you can through the Executors. NewSingleThreadExecutor () created the execute method of the single thread thread pool threads execute a.

The execute method takes an object of a class that implements the Runnable interface, either an actual class or an anonymous class, which is used in this example.

In this example, the request is processed asynchronously using a single thread pool.

3,

Future<Integer> future = es.submit(new Callable<Integer>()
{
    @Override
    public Integer call()
        throws Exception
    {
        try
        {
            Thread.sleep(100);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        System.out.println("TaskFlag: " + count + ", Install MCS plugins " + task + " is working.");
        return(new Random(1000)).nextInt(); }}); futures.put(task, future);Copy the code

Let’s take a look at the thread pool used in this example: es

Similarly, newFixedThreadPool returns an ExecutorService object. In Java source code, this method returns a LinkedBlockingQueue

object. But this article does not explain in detail, interested in further reading Java source code; In this example, submit is used to perform a task:

Future<Integer> future = es.submit(new Callable<Integer>()
{
    @Override
    public Integer call()
        throws Exception
    {
        //do something                            
        return(new Random(1000)).nextInt(); }});Copy the code

There are three differences from the single thread pool we created in the previous step.

  • 1. The single thread pool is not usedFutureObject to query the return result
  • 2. Single thread pool usageexecuteThe fixed length thread pool is usedsubmitIn the manner of execution;
  • 3. Use implementations for single-threaded executionRunnableInterface class, fixed length thread pool using implementationCallableInterface classes;

Let’s do it one by one

  • 1. The single thread pool is not usedFutureObject to return a result queryFutureClass: Let’s have a look firstsubmitMethod definition:

I have a brief translation of this note:

Submit a task with a return value. The method will return a result of type Future. The future-provided GET function will get the result of the thread's execution after it has fully executed. The annotation provides a brief explanation of the Future type: represents the execution result of a pending task.Copy the code

The definition of the Future type is found:

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}
Copy the code

Official notes for a more detailed explanation (here is the focus)

Represents the result of an asynchronous calculation. Methods are provided to check that the calculation is complete, wait for the calculation to complete, and retrieve the result of the calculation. Only after the calculation is complete can the result be retrieved using the @code get method, blocking it if necessary until it is ready. Cancellation is performed by the @code Cancel method. Additional methods are provided to determine whether a task completed properly or was cancelled. Once the calculation is complete, it cannot be cancelled.

I don’t think we need to explain too much about why Future is used: We use the Future as a fetch for the execution result of the task, and this fetch is asynchronous, so when we submit a task through submit, we return a Future object as the control object of the current submission thread

Conclusion: In this case, you need to manipulate the execution result, so use the Future object;

  • 2. Single thread pool usageexecuteThe fixed length thread pool is usedsubmitIn the manner of execution?

From a brief analysis of the first problem, it is clear that in this case, we need to process the result of execution (although in this case we are only printing), so the thread object we are executing must return a value. Execute provided by the Executor interface does not return a value.

  • 3. Use implementations for single-threaded executionRunnableInterface class, fixed length thread pool using implementationCallableInterface classes; After analyzing the above two problems, the third problem is easily solvedRunnableThreads are not supported to return results, whileCallableInterface support;

Through the brief analysis of the above three points, the following conclusions can be drawn:

  • 1.RunnablewithCallableThe core difference between:RunnableThreads are not supported to return results, whileCallableInterface support;
  • 2,submitwithexecuteThe same function is used to execute threads in the thread pool, butexecuteNo return value, butsubmitReturns the execution result of the thread,submitYou can also submitRunnableInterface implementation thread object

  • The Future object can take control of the thread of execution, stop the thread, and get the result of the thread by blocking.

The execution result

TaskFlag: 5, Install MCS plugins 3 is working.
TaskFlag: 5, Install MCS plugins 2 is working.
TaskFlag: 5, Install MCS plugins 1 is working.
TaskFlag: 5, Install MCS plugins 5 is working.
taskID: 1, Res: -1244746321
taskID: 2, Res: -1244746321
taskID: 3, Res: -1244746321
TaskFlag: 5, Install MCS plugins 4 is working.
taskID: 4, Res: -1244746321
taskID: 5, Res: -1244746321
5 个 安装MCS 插件任务submit完成!Time:114
Executors.newSingleThreadExecutor().execute : shutdown后退出! Time:114
submit task all
TaskFlag: 50, Install MCS plugins 4 is working.
TaskFlag: 50, Install MCS plugins 2 is working.
TaskFlag: 6, Install MCS plugins 1 is working.
TaskFlag: 50, Install MCS plugins 3 is working.
TaskFlag: 6, Install MCS plugins 2 is working.
taskID: 1, Res: -1244746321
taskID: 2, Res: -1244746321
TaskFlag: 6, Install MCS plugins 5 is working.
TaskFlag: 6, Install MCS plugins 3 is working.
taskID: 3, Res: -1244746321
TaskFlag: 6, Install MCS plugins 6 is working.
TaskFlag: 4, Install MCS plugins 3 is working.
TaskFlag: 50, Install MCS plugins 8 is working.
TaskFlag: 4, Install MCS plugins 2 is working.
TaskFlag: 50, Install MCS plugins 7 is working.
TaskFlag: 4, Install MCS plugins 4 is working.
TaskFlag: 4, Install MCS plugins 1 is working.
TaskFlag: 50, Install MCS plugins 9 is working.
taskID: 1, Res: -1244746321
TaskFlag: 50, Install MCS plugins 10 is working.
taskID: 2, Res: -1244746321
taskID: 3, Res: -1244746321
taskID: 4, Res: -1244746321
4 个 安装MCS 插件任务submit完成!Time:104
Executors.newSingleThreadExecutor().execute : shutdown后退出! Time:104
TaskFlag: 50, Install MCS plugins 6 is working.
TaskFlag: 50, Install MCS plugins 5 is working.
TaskFlag: 6, Install MCS plugins 4 is working.
taskID: 4, Res: -1244746321
taskID: 5, Res: -1244746321
taskID: 6, Res: -1244746321
6 个 安装MCS 插件任务submit完成!Time:105
Executors.newSingleThreadExecutor().execute : shutdown后退出! Time:105
TaskFlag: 50, Install MCS plugins 1 is working.
taskID: 1, Res: -1244746321
taskID: 2, Res: -1244746321
taskID: 3, Res: -1244746321
taskID: 4, Res: -1244746321
taskID: 5, Res: -1244746321
taskID: 6, Res: -1244746321
taskID: 7, Res: -1244746321
taskID: 8, Res: -1244746321
taskID: 9, Res: -1244746321
taskID: 10, Res: -1244746321
TaskFlag: 50, Install MCS plugins 11 is working.
taskID: 11, Res: -1244746321
TaskFlag: 50, Install MCS plugins 13 is working.
TaskFlag: 50, Install MCS plugins 12 is working.
taskID: 12, Res: -1244746321
taskID: 13, Res: -1244746321
TaskFlag: 50, Install MCS plugins 16 is working.
TaskFlag: 50, Install MCS plugins 14 is working.
TaskFlag: 50, Install MCS plugins 17 is working.
TaskFlag: 50, Install MCS plugins 19 is working.
TaskFlag: 50, Install MCS plugins 21 is working.
TaskFlag: 50, Install MCS plugins 18 is working.
TaskFlag: 50, Install MCS plugins 15 is working.
TaskFlag: 50, Install MCS plugins 28 is working.
TaskFlag: 50, Install MCS plugins 26 is working.
TaskFlag: 50, Install MCS plugins 24 is working.
TaskFlag: 50, Install MCS plugins 27 is working.
TaskFlag: 50, Install MCS plugins 29 is working.
TaskFlag: 50, Install MCS plugins 20 is working.
taskID: 14, Res: -1244746321
taskID: 15, Res: -1244746321
taskID: 16, Res: -1244746321
taskID: 17, Res: -1244746321
taskID: 18, Res: -1244746321
taskID: 19, Res: -1244746321
taskID: 20, Res: -1244746321
taskID: 21, Res: -1244746321
TaskFlag: 50, Install MCS plugins 25 is working.
TaskFlag: 50, Install MCS plugins 23 is working.
TaskFlag: 50, Install MCS plugins 22 is working.
taskID: 22, Res: -1244746321
taskID: 23, Res: -1244746321
taskID: 24, Res: -1244746321
taskID: 25, Res: -1244746321
taskID: 26, Res: -1244746321
taskID: 27, Res: -1244746321
taskID: 28, Res: -1244746321
taskID: 29, Res: -1244746321
TaskFlag: 50, Install MCS plugins 30 is working.
taskID: 30, Res: -1244746321
TaskFlag: 50, Install MCS plugins 31 is working.
taskID: 31, Res: -1244746321
TaskFlag: 50, Install MCS plugins 33 is working.
TaskFlag: 50, Install MCS plugins 32 is working.
taskID: 32, Res: -1244746321
taskID: 33, Res: -1244746321
TaskFlag: 50, Install MCS plugins 34 is working.
taskID: 34, Res: -1244746321
TaskFlag: 50, Install MCS plugins 37 is working.
TaskFlag: 50, Install MCS plugins 36 is working.
TaskFlag: 50, Install MCS plugins 35 is working.
taskID: 35, Res: -1244746321
taskID: 36, Res: -1244746321
taskID: 37, Res: -1244746321
TaskFlag: 50, Install MCS plugins 45 is working.
TaskFlag: 50, Install MCS plugins 38 is working.
TaskFlag: 50, Install MCS plugins 40 is working.
TaskFlag: 50, Install MCS plugins 42 is working.
taskID: 38, Res: -1244746321
TaskFlag: 50, Install MCS plugins 44 is working.
TaskFlag: 50, Install MCS plugins 43 is working.
TaskFlag: 50, Install MCS plugins 41 is working.
TaskFlag: 50, Install MCS plugins 39 is working.
taskID: 39, Res: -1244746321
taskID: 40, Res: -1244746321
taskID: 41, Res: -1244746321
taskID: 42, Res: -1244746321
taskID: 43, Res: -1244746321
taskID: 44, Res: -1244746321
taskID: 45, Res: -1244746321
TaskFlag: 50, Install MCS plugins 49 is working.
TaskFlag: 50, Install MCS plugins 48 is working.
TaskFlag: 50, Install MCS plugins 47 is working.
TaskFlag: 50, Install MCS plugins 46 is working.
taskID: 46, Res: -1244746321
taskID: 47, Res: -1244746321
taskID: 48, Res: -1244746321
taskID: 49, Res: -1244746321
TaskFlag: 50, Install MCS plugins 50 is working.
taskID: 50, Res: -1244746321
50 个 安装MCS 插件任务submit完成!Time:308
Executors.newSingleThreadExecutor().execute : shutdown后退出! Time:308
Copy the code

supplement

  • The get method provided by the Future will block. It will block the current running method until a result is returned.

  • ExecutorService provides the shutdown method and shutdownNow method. The difference is that shutdown and all threads in the thread pool wait queue will exit after execution. ShutdownNow is a forcible exit, regardless of whether a task has been executed.