You get a Java thread pool

Disclaimer: This article is a blogger original article, please indicate the source. Welcome to public concern number: Java Notes Share (xiaosen_javashare) https://blog.csdn.net/qq_36447151/article/details/87793009

Welcome attention to micro-channel public number: xiaosen_javashare
In the previous article "spring boot using @Async asynchronous task" in our understanding of the asynchronous tasks that use @Async, and in this article we will learn to create an asynchronous task threads using a thread pool .

In the "Ali Baba Java Developer's Handbook" has the following requirements for the use of threads:

Next, let us just take a look at the thread pool.

Thread Pool brief

Executor Java5 incorporated in the frame.

ThreadPoolExecutor parsing thread pool

Class diagram which follows:

The figure is ThreadPoolExecutor Constructor:

We see most of the configuration parameters is the most complete method here:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
                              long keepAliveTime, TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 || maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize || keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ? null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
  1. corePoolSize (basic thread pool size): When submitting a task to the thread pool, thread pool will create a thread to perform the task, even if the other free basic thread can perform new tasks will be to create a thread, until the number of tasks you need to perform is greater than it is no longer essential to create a thread pool size. If you call a method prestartAllCoreThreads thread pool, thread pool is created in advance and start all basic threads.
  2. maximumPoolSize (maximum thread pool size): thread pool allows you to create the maximum number of threads. If the queue is full, and the number of threads that have been created less than the maximum number of threads, the thread pool will re-create a new thread to perform the task. It is worth noting that if you use unbounded task queue this parameter to no effect.
  3. keepAliveTime (thread activity hold time): After the thread pool worker thread is idle, keeping alive the time. So if a lot of tasks, and each task execution time is relatively short, it can turn up this time, improve the utilization of the thread.
  4. TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
  5. workQueue (任务队列):用于保存等待执行的任务的阻塞队列。可以选择以下几个阻塞队列。
    1. ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
    2. LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
    3. SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
    4. PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
  1. ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程做些更有意义的事情,比如设置daemon和优先级等等

  2. RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。

    1. AbortPolicy:直接抛出异常。
    2. CallerRunsPolicy:只用调用者所在线程来运行任务。
    3. DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
    4. DiscardPolicy:不处理,丢弃掉。
    5. 也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
线程池的工作方式
  1. 如果运行的线程少于 corePoolSize,则 Executor 始终创建新的线程,而不添加到queue中。
  2. 如果运行的线程等于或多于 corePoolSize,则 Executor 始终将请求加入队列,而不创建新的线程。
  3. 如果无法将请求加入队列(队列已满),则创建新的线程,除非创建此线程超出 maximumPoolSize,如果超过,在这种情况下,新的任务将被拒绝。

Executors提供的线程池方法

  1. newFixedThreadPool固定线程数的线程。
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

从上面源代码可以看出新创建的newFixedThreadPool的corePoolSize和maximumPoolSize都被设置为nThreads。

说明:

  1. 如果当前运行的线程数小于corePoolSize,则创建新的线程来执行任务;
  2. 当前运行的线程数等于corePoolSize后,将任务加入LinkedBlockingQueue;
  3. 线程执行完1中的任务后,会在循环中反复从LinkedBlockingQueue中获取任务来执行。

FixedThreadPool使用无界队列 LinkedBlockingQueue(队列的容量为Intger.MAX_VALUE)作为线程池的工作队列会对线程池带来如下影响:

  1. 当线程池中的线程数达到corePoolSize后,新任务将在无界队列中等待,因此线程池中的线程数不会超过corePoolSize;
  2. 使用无界队列时maximumPoolSize和keepAliveTime将是无效参数;
  3. 运行中的newFixedThreadPool(未执行shutdown()或shutdownNow()方法)不会拒绝任务。
  1. newSingleThreadExecutor单个线程的线程池
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

从上面源代码可以看出新创建的SingleThreadExecutor的corePoolSize和maximumPoolSize都被设置为1.其他参数和newFixedThreadPool相同。也是用的是无界队列存放。

说明:

  1. 如果当前运行的线程数少于corePoolSize,则创建一个新的线程执行任务;
  2. 当前线程池中有一个运行的线程后,将任务加入LinkedBlockingQueue
  3. 线程执行完1中的任务后,会在循环中反复从LinkedBlockingQueue中获取任务来执行。
  1. newCachedThreadPool, 先看一下源码:
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }

newCachedThreadPool的corePoolSize是0,maximumPoolSize被设置为Integer.MAX.VALUE。

说明:

  1. SynchronousQueue是无界的,在某次添加元素后必须等待其他线程取走后才能继续添加。
  2. 如果无法将请求加入队列,则创建新的线程,除非创建此线程超出maximumPoolSize,在这种情况下,任务将被拒绝。
  1. ScheduledExecutorService,此线程池支持定时以及周期性执行任务的需求。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }

我们再看一下ScheduledThreadPoolExecutor中的源码:

public ScheduledFuture<?> schedule(Runnable command,
                                       long delay,
                                       TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        RunnableScheduledFuture<?> t = decorateTask(command,
            new ScheduledFutureTask<Void>(command, null,
                                          triggerTime(delay, unit)));
        delayedExecute(t);
        return t;
    }

调用schedule方法,delay是延迟多少时间执行。

以上就是Executors提供的几种常见的线程池的解析。

ThreadPoolTaskExecutor

下面我们来看一下spring为我们提供的线程池ThreadPoolTaskExecutor。下图是其类关系图:

	private final Object poolSizeMonitor = new Object();

	private int corePoolSize = 1;

	private int maxPoolSize = Integer.MAX_VALUE;

	private int keepAliveSeconds = 60;

	private int queueCapacity = Integer.MAX_VALUE;

	private boolean allowCoreThreadTimeOut = false;

	@Nullable
	private TaskDecorator taskDecorator;

	@Nullable
	private ThreadPoolExecutor threadPoolExecutor;

这是ThreadPoolTaskExecutor类中的属性,可以看出依然需要ThreadPoolExecutor类来支持。默认使用无界队列。

在初始化方法中调用了ThreadPoolExecutor的构造器:

@Override
	protected ExecutorService initializeExecutor(
			ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {

		BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);

		ThreadPoolExecutor executor;
		if (this.taskDecorator != null) {
			executor = new ThreadPoolExecutor(
					this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
					queue, threadFactory, rejectedExecutionHandler) {
				@Override
				public void execute(Runnable command) {
					Runnable decorated = taskDecorator.decorate(command);
					if (decorated != command) {
						decoratedTaskMap.put(decorated, command);
					}
					super.execute(decorated);
				}
			};
		}
		else {
			executor = new ThreadPoolExecutor(
					this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
					queue, threadFactory, rejectedExecutionHandler);

		}

		if (this.allowCoreThreadTimeOut) {
			executor.allowCoreThreadTimeOut(true);
		}

		this.threadPoolExecutor = executor;
		return executor;
	}

说明:

  1. Line city (threadPoolTaskExecutor) spring configuration because it is spring created injected, after the first use, it will remain corePoolSize idle threads, it only will the excess idle threads released after keepAliveSeconds time, and line the city can not call shutdown () method, otherwise called again, because the thread pool has been closed, will complain.
  2. threadPoolTaskExecutor may be arranged in a plurality of profile lines city, to prevent competition between the multi-task, or due to different size city where lines used for different tasks and the like.

to sum up

More than a brief introduction to the thread pool java comes with four thread pools and spring offer their own advantages and disadvantages, actual project can be selected according to the needs.


Welcome to public concern number:
Welcome to public concern No.

Guess you like

Origin blog.csdn.net/qq_36447151/article/details/87793009