创建线程池
执行说明
图解
步骤
- 1、创建线程池对线时候不会创建线程,当有第一个线程任务时,才会创建线程。
- 2、如果线程数少于核心线程数时,当有新的线程来,不管之前的线程是否空闲,都会继续创建新的线程,直到达到核心线程数。
- 3、当线程数等于核心线程数时,当有新线程来,先放入任务队列中等待核心线程执行完毕之后取出任务队列中任务执行,直到线程队列达到最大容量。
- 4、当线程数大于队列最大容量时候,会创建非核心线程来执行任务,直到达到最大线程数(maximumPoolSize)。
- 5、当线程数等于最大线程数时,触发线程池拒绝策略(RejectedExecutionHandler)。
例子
corePoolSize为5,maximumPoolSize为10,workQueue的size为100。
当请求来时,最多创建5个核心线程来执行任务,剩下的被添加到任务队列,当队列慢了后会创建非核心线程执行任务直到10个,再来任务就拒绝。
构造函数
ExecutorService executorService = new ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler);
参数说明:
- corePoolSize:核心线程数。一旦创建,就不会被释放销毁。
- maximumPoolSize:最大线程数。线程池允许创建的最大线程数量。
- keepAliveTime:线程空闲时间。达到这个时间非核心线程将会被回收销毁。(allowCoreThreadTimeOut修改这个属性为ture,核心线程也会被回收)
- unit:线程空闲时间单位。
- workQueue:任务队列。当任务对大于核心线程时候,就会被放到这个队列中等待。
- threadFactory:线程工厂。创建新线程时,通过线程工厂来创建。
- handler:线程池拒绝策略。
workQueue任务队列
SynchronousQueue:同步阻塞单一队列
该队列put之后会阻塞当前线程,阻塞到等有别的线程来拿走。同步队列没有任何内部容量。不要使用add,因为这个队列内部没有任何容量,所以会抛出异常“IllegalStateException”。翻译一下:这是一个内部没有任何容量的阻塞队列,任何一次插入操作的元素都要等待相对的删除/读取操作,否则进行插入操作的线程就要一直等待,反之亦然。
不需要队列存储的时候就会使用这种,比如Executors.newCachedThreadPool()。
示例:
package com.weilai;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
/**
* @author weilai
* @email 352342845@qq.com
* @date 2019-12-02 10:53
*/
public class ThreadLocalTest {
public static void main(String[] args) {
SynchronousQueue<String> queue = new SynchronousQueue<>();
// 不要使用add,因为这个队列内部没有任何容量,所以会抛出异常“IllegalStateException”
// queue.add(new Object());
ExecutorService service = Executors.newSingleThreadExecutor();
service.submit( () -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String poll = queue.poll();
System.out.println(poll);
});
try {
System.out.println(1);
// 操作线程会在这里被阻塞,直到有其他操作线程取走这个对象
queue.put("hello");
System.out.println(2);
} catch (InterruptedException e) {
e.printStackTrace