Executor class creates four common thread pool

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/ThinkWon/article/details/102541990

Thread pool architecture

Here Insert Picture Description

The figure is a schematic diagram of the thread pool. Java thread pool inside the top-level interface is Executor, Executor not a thread

Pool, but only one thread of execution tool. The real thread pool interface is a ExecutorService.

The more important categories:

Class / interface description
ExecutorService The real thread pool Interface
ScheduledExecutorService Energy and Timer / TimerTask similar, problem-solving tasks that require repeated execution
ThreadPoolExecutor The default implementation ExecutorService
ScheduledThreadPoolExecutor ScheduledExecutorService interface inheritance ThreadPoolExecutor, periodic task scheduling class implementation

To configure a thread pool is more complex, especially for under the principle of the thread pool is not very clear, the likely configuration of the thread pool is not superior, thus providing some static factory Executors class which generates some commonly used the thread pool.

By Java provides four thread pool Executors factory class , namely:

  1. newCachedThreadPool : Create a cache thread pool, thread pool longer than if treatment needs, the flexibility to reclaim idle thread, if not recyclable, or create a new thread. (Maximum number of concurrent threads uncontrollable)
  2. newFixedThreadPool : create a fixed-size thread pool, you can control the maximum number of concurrent threads, excess threads will wait in the queue.
  3. newScheduledThreadPool : Creating a timer thread pool to support regular and periodic task execution.
  4. newSingleThreadExecutor : create a single-threaded thread pool, use it only to perform the task only worker threads to ensure that all tasks are performed in a specified order (FIFO, LIFO, priorities).

Let's create a unified thread task, convenient test four kinds of thread pool

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " is running...");
    }

}

newSingleThreadExecutor

public class SingleThreadExecutorTest {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        MyRunnable myRunnable = new MyRunnable();
        for (int i = 0; i < 5; i++) {
            executorService.execute(myRunnable);
        }

        System.out.println("线程任务开始执行");
        executorService.shutdown();
    }

}

Output

线程任务开始执行
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-1 is running...

The underlying implementation

/**
 * 核心线程池大小=1
 * 最大线程池大小为1
 * 线程过期时间为0ms
 * LinkedBlockingQueue作为工作队列
 */
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

Can be seen from the parameters, SingleThreadExecutor equivalent special FixedThreadPool, its execution process is as follows:

  1. When there is no thread pool thread, a new thread to perform tasks
  2. There is a thread in the future, the task to the blocked queue, plus non-stop
  3. This is only a thread to keep taking the task execution queue

SingleThreadExecutor scenario for serial execution of tasks, each task must be performed in order, need not be executed concurrently .

newFixedThreadPool

public class FixedThreadPoolTest {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        MyRunnable myRunnable = new MyRunnable();
        for (int i = 0; i < 5; i++) {
            executorService.execute(myRunnable);
        }

        System.out.println("线程任务开始执行");
        executorService.shutdown();
    }

}

Output

线程任务开始执行
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-2 is running...
pool-1-thread-1 is running...
pool-1-thread-2 is running...

The underlying implementation

/**
 * 核心线程池大小=传入参数
 * 最大线程池大小为传入参数
 * 线程过期时间为0ms
 * LinkedBlockingQueue作为工作队列
 */
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

You can see, the core number of threads and the maximum number of threads FixedThreadPool are designated value, that is, when the number of threads in the thread pool threads exceeds the number of cores, the task will be placed in the blocking queue.

In addition keepAliveTime is 0, that is, the excess of free threads will be terminated immediately (Because there is no extra thread, this parameter is also no sense).

And here is the selection of a LinkedBlockingQueue blocking queue, Integer.MAX_VALUE default capacity is used, corresponding to no upper limit.

Therefore, this thread pool to perform tasks process is as follows:

  1. When the number of threads less than the core number of threads, which is the number of threads, the new thread to perform tasks
  2. After the core number of threads equal to the number of threads, the task to the blocked queue
  3. Because the queue capacity is very large, you can always add
  4. Thread executing the task repeatedly taken to task execution queue

FixedThreadPool heavier load for the server to the rational use of resources, the need to limit the number of the current thread .

newCachedThreadPool

public class CachedThreadPoolTest {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        MyRunnable myRunnable = new MyRunnable();
        for (int i = 0; i < 5; i++) {
            executorService.execute(myRunnable);
        }

        System.out.println("线程任务开始执行");
        executorService.shutdown();
    }

}

Output

线程任务开始执行
pool-1-thread-1 is running...
pool-1-thread-4 is running...
pool-1-thread-2 is running...
pool-1-thread-5 is running...
pool-1-thread-3 is running...

The underlying implementation

/**
 *  核心线程池大小=0
 *  最大线程池大小为Integer.MAX_VALUE
 *  线程过期时间为60s
 *  使用SynchronousQueue作为工作队列
 */
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

You can see, CachedThreadPool no core thread, the number of non-core thread is no upper limit, that is, all use of outsourcing, but each outsourcing idle time only 60 seconds, and will be recovered after more than.

Queue CachedThreadPool using SynchronousQueue, this role is to transfer the task queue, and will not be saved.

Therefore, when the speed is greater than the speed of processing tasks submitted to the task, each commit a task, it will create a thread. It creates too many threads in extreme cases, run out of CPU and memory resources.

Its implementation process is as follows:

  1. No core thread, submit jobs directly to the SynchronousQueue
  2. If there is idle thread, and went out to perform the task; if there is no idle thread, create a new one
  3. Thread executing the tasks have 60 seconds time to live, if you can receive new tasks within this time, we can continue to live, otherwise bye
  4. Since the free 60-second thread will be terminated, for a long time remain idle CachedThreadPool not take up any resources.

CachedThreadPool for concurrent execution of a large number of small short-term task, or lightly loaded servers .

newScheduledThreadPool

public class ScheduledThreadPoolTest {

    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        MyRunnable myRunnable = new MyRunnable();
        for (int i = 0; i < 5; i++) {
            // 参数1:目标对象,参数2:隔多长时间开始执行线程,参数3:执行周期,参数4:时间单位
            scheduledExecutorService.scheduleAtFixedRate(myRunnable, 1, 2, TimeUnit.SECONDS);
        }

        System.out.println("线程任务开始执行");
    }

}

Output

线程任务开始执行
// 打印【线程任务开始执行】后1秒输出
pool-1-thread-1 is running...
pool-1-thread-2 is running...
pool-1-thread-1 is running...
pool-1-thread-3 is running...
pool-1-thread-2 is running...
// 2秒后输出
pool-1-thread-1 is running...
pool-1-thread-3 is running...
pool-1-thread-2 is running...
pool-1-thread-1 is running...
pool-1-thread-3 is running...

The underlying implementation

/**
 * 核心线程池大小=传入参数
 * 最大线程池大小为Integer.MAX_VALUE
 * 线程过期时间为0ms
 * DelayedWorkQueue作为工作队列
 */
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}

ScheduledThreadPoolExecutor implementation process is as follows:

  1. Add a task
  2. Threads in the pool to take the job from DelayQueue
  3. Then perform the task

Specific steps to perform tasks is more complex:

  1. Greater than or equal thread gets time from the current time ScheduledFutureTask in DelayQueue

  2. After the implementation of this task to modify the time for the next time to be executed

  3. The task then put back into the queue

ScheduledThreadPoolExecutor need for more background thread to perform periodic tasks, and the need to limit the number of threads scene .

Executors and create differences ThreaPoolExecutor thread pool

Executors disadvantages of each method:

  1. newFixedThreadPool and newSingleThreadExecutor:
    The main problem is the accumulation of request processing queue may consume very large memory, even OOM.
  2. newCachedThreadPool and newScheduledThreadPool:
    The main problem is the maximum number of threads is Integer.MAX_VALUE, may create a very large number of threads, even OOM.

ThreaPoolExecutor

  1. Only one way to create a thread pool, is to take its constructor, specify the parameters yourself

Two methods to deliver the task

ExecutorService provides two ways to submit tasks:

  • execute (): Returns the task does not need to submit values
  • submit (): Returns the tasks required to submit value

execute

void execute(Runnable command);

Parameters execute () is a Runnable, there is no return value. Therefore, after the submission can not determine whether the task is successfully executed thread pool.

ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(new Runnable() {
    @Override
    public void run() {
        //do something
    }
});

submit

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

submit () There are three heavy-duty, can be Callable parameters can also be a Runnable.

At the same time it will return a Funture objects, through which we can determine whether to perform the task successfully.

The results obtained call Future.get () method, this method blocks the current thread until the task is completed.

When submitting a Callable task that requires the use of FutureTask one package:

FutureTask futureTask = new FutureTask(new Callable<String>() {    //创建 Callable 任务
    @Override
    public String call() throws Exception {
        String result = "";
        //do something
        return result;
    }
});
Future<?> submit = executor.submit(futureTask);    //提交到线程池
try {
    Object result = submit.get();    //获取结果
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}

Guess you like

Origin blog.csdn.net/ThinkWon/article/details/102541990