Java ExecutorService uses four thread pools

1. Introduction The rational use of thread pools can bring three benefits. First: reduce resource consumption. Reduce the cost of thread creation and destruction by reusing already created threads. Second: improve the response speed. When a task arrives, the task can execute immediately without waiting until the thread is created. Third: improve the manageability of threads. Threads are scarce resources. If they are created without restrictions, it will not only consume system resources, but also reduce the stability of the system. Using thread pools can be used for unified allocation, tuning, and monitoring. But to make reasonable use of the thread pool, you must know its principles well.

2. The thread pool uses the four types of threads provided by Executors 1. newCachedThreadPool creates a cacheable thread pool. If the length of the thread pool exceeds the processing requirement, idle threads can be flexibly recovered. If there is no recovery, a new thread will be created. 2. newFixedThreadPool creates a fixed-length thread pool, which can control the maximum number of concurrent threads, and the excess threads will wait in the queue. 3. newScheduledThreadPool creates a fixed-length thread pool that supports timing and periodic task execution. 4. newSingleThreadExecutor creates a single-threaded thread pool, which only uses a single worker thread to execute tasks, ensuring that all tasks are executed in the specified order (FIFO, LIFO, priority).

1. newCachedThreadPool creates a cacheable thread pool. If the length of the thread pool exceeds the processing needs, it can flexibly recycle idle threads. If there is no recovery, create a new thread. Examples are as follows

ExecutorService executorService = Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
    final int index = i;
    try {
        Thread.sleep(index * 1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() +  "," +index);
        }
    });
}
//控制台信息
pool-1-thread-1,0
pool-1-thread-1,1
pool-1-thread-1,2
pool-1-thread-1,3
pool-1-thread-1,4

2. newFixedThreadPool creates a fixed-length thread pool, which can control the maximum number of concurrent threads, and the excess threads will wait in the queue. Examples are as follows

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
for(int i=0;i<5;i++) {
    final int index = i;
       fixedThreadPool.execute(new Runnable() {
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + ", " + index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}
//控制台信息
pool-1-thread-1,0
pool-1-thread-2,1
pool-1-thread-3,2
pool-1-thread-4,3
pool-1-thread-1,4

3. newScheduledThreadPool creates a fixed-length thread pool that supports cycles and timed tasks. Examples are as follows

ScheduledExecutorService scheduledThreadPool =  Executors.newScheduledThreadPool(5);
System.out.println("before:" + System.currentTimeMillis()/1000);
scheduledThreadPool.schedule(new Runnable() {
    @Override
    public void run() {
        System.out.println("延迟3秒执行的哦 :" + System.currentTimeMillis()/1000);
    }
}, 3, TimeUnit.SECONDS);
System.out.println("after :" +System.currentTimeMillis()/1000);
//控制台信息
before:1518012703
after :1518012703
延迟3秒执行的哦 :1518012706
System.out.println("before:" + System.currentTimeMillis()/1000);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        System.out.println("延迟1秒之后,3秒执行一次:" +System.currentTimeMillis()/1000);
    }
}, 1, 3, TimeUnit.SECONDS);
System.out.println("after :" +System.currentTimeMillis()/1000);
控制台消息
before:1518013024
after :1518013024
延迟1秒之后,3秒执行一次:1518013025
延迟1秒之后,3秒执行一次:1518013028
延迟1秒之后,3秒执行一次:1518013031

4. newSingleThreadExecutor creates a single-threaded thread pool, which only uses worker threads to execute tasks and guarantees the order. The example is as follows

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i=0;i<10;i++) {
    final int index = i;
    singleThreadExecutor.execute(new Runnable() {
        @Override
        public void run() {
            try {
                  System.out.println(Thread.currentThread().getName() + "," + index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}
//控制台信息
pool-1-thread-1,0
pool-1-thread-1,1
pool-1-thread-1,2
pool-1-thread-1,3
pool-1-thread-1,4

Submitting tasks to the thread pool The difference between execute() and submit() in the ThreadPoolExecutor class The execute() method is actually a method declared in Executor, which is specifically implemented in ThreadPoolExecutor. This method is the core method of ThreadPoolExecutor. The thread pool submits a task for execution by the thread pool.

The submit() method is a method declared in ExecutorService. It has been implemented in AbstractExecutorService. It is not rewritten in ThreadPoolExecutor. This method is also used to submit tasks to the thread pool, but it is different from execute() ) method is different, it can return the result of the task execution, check the implementation of the submit() method through the source code, you will find that it is actually the execute() method called, but it uses the Future to obtain the task execution result.

/**
 * @throws RejectedExecutionException {@inheritDoc}
 * @throws NullPointerException       {@inheritDoc}
 */
public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

Closing the thread pool We can close the thread pool by calling the shutdown or shutdownNow methods of the thread pool, but their implementation principles are different. The principle of shutdown is to just set the state of the thread pool to the SHUTDOWN state, and then interrupt all tasks that are not executing. thread. The principle of shutdownNow is to traverse the worker threads in the thread pool, and then call the interrupt method of the thread one by one to interrupt the thread, so the task that cannot respond to the interruption may never be terminated. shutdownNow will first set the state of the thread pool to STOP, then try to stop all threads that are executing or suspending tasks, and return the list of tasks waiting to be executed.

The isShutdown method returns true whenever one of these two shutdown methods is called. When all tasks have been closed, it means that the thread pool is closed successfully, then calling the isTerminaed method will return true. As for which method we should call to close the thread pool, it should be determined by the characteristics of the tasks submitted to the thread pool. Usually, shutdown is called to close the thread pool. If the task does not have to be executed, shutdownNow can be called.

3. Analysis of the thread pool analysis process : The main workflow of the thread pool is as follows:The main workflow of the Java thread pool

As can be seen from the above figure, when a new task is submitted to the thread pool, the processing flow of the thread pool is as follows:

  1. First, the thread pool determines whether the basic thread pool is full? Not full, create a worker thread to execute the task. If it is full, go to the next process.
  2. Secondly, the thread pool determines whether the work queue is full? If it is not full, the newly submitted task is stored in the work queue. If it is full, go to the next process.
  3. Finally, the thread pool determines whether the entire thread pool is full? If it is not full, a new worker thread is created to execute the task, and when it is full, it is handed over to the saturation strategy to process the task.

**Source code analysis. **The above process analysis allows us to intuitively understand the working principle of the thread pool, let us see how it is implemented through the source code. The thread pool executes tasks as follows:

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)) {
        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);
}

worker thread . When the thread pool creates a thread, it will encapsulate the thread into a worker thread Worker. After the worker finishes executing the task, it will obtain the tasks in the work queue in an infinite loop for execution. ▼Long press the QR code below to follow▼ imagePlease join me to fight monsters and upgrade in 2018

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325513032&siteId=291194637