JAVA线程池基础知识解析

线程池是什么?

线程池是一种集中管理多线程的容器,线程使用完不会销毁,会先储存在线程池中,在处理过多任务时会将任务添加到队列中,然后在创建线程后自动启动这些任务。

为什么要使用线程池?

1:减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2:可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

线程池工作流程

在这里插入图片描述
创建完线程池后并不会立即创建线程, 而是等到有任务提交时才会创建线程来进行处理。
每当有新任务请求进入线程池中
1:判断核心线程数(corePoolSize)是否饱和,如果不饱和则创建新线程执行任务请求,反之则继续
2:判断工作队列(corePoolSize)是否饱和,如果不饱和则将任务放入工作队列中,反之则继续
3:判断最大线程数(maximumPoolSize)是否饱和,如果不饱和则创建新的线程执行任务请求,反之则执行饱和策略

自定义线程池参数解析

//源码默认至少要传入的参数corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue
//可以看出
//默认的线程工厂是Executors.defaultThreadFactory()
//默认的饱和策略是AbortPolicy
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

/**		 自定义创建线程池
         * @param corePoolSize      核心线程数  5
         * @param maximumPoolSize   最大线程数  10
         * @param keepAliveTime     空闲线程存活时间    60
         * @param unit              空闲线程存活时间单位	SECONDS秒
         * @param workQueue         工作队列 
         * @param threadFactory     线程工厂(默认defaultThreadFactory)
         * @param handler           处理饱和状态机制(默认AbortPolicy)
         */
        ExecutorService customThread = new ThreadPoolExecutor(5,10,60,
        		TimeUnit.SECONDS,new LinkedBlockingQueue<>(),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

解析源码七大参数含义:

一:corePoolSize 核心线程数

线程池中最小的线程数量,即使这些线程处理空闲状态且超过了keepAliveTime,他们也不会被销毁,除非设置allowCoreThreadTimeOut。

二:maximumPoolSize 最大线程数

线程池不会无限制的去创建新线程,最大线程数量由maximunPoolSize来决定。

三:keepAliveTime 空闲线程存活时间

一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在超过keepAliveTime时间后,这个空闲线程会被销毁。

四:unit 空闲线程存活时间单位

keepAliveTime的时间单位

五:workQueue 工作队列

JAVA中提供了几种类型的workQueue,前三种使用比较广泛

  1. ArrayBlockingQueue
    有界(数组)队列,遵循FIFO,新任务进来后,会放到队列的队尾。因为没有无参数构造器,必须给定初始队列大小参数。
    当线程数量已经达到maxPoolSize,则会执行拒绝策略。

  2. LinkedBlockingQuene
    无界(链表)队列,遵循FIFO,

//默认容量为Interger.MAX
public LinkedBlockingQueue() {
  this(Integer.MAX_VALUE);
}

如果使用无参构造器,当线程池中线程数量达到corePoolSize后,再有新任务进来,由于队列容量是Integer.MAX_VALUE,容量可认为无限大,任务会一直存入该队列,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。如果使用传入容量大小maxPoolSize才能起作用

//也可自定义容量大小
public LinkedBlockingQueue(int capacity) {
    if (capacity <= 0) throw new IllegalArgumentException();
    this.capacity = capacity;
    last = head = new Node<E>(null);
}
  1. SynchronousQuene
    SynchronousQuene不是一个真正意义上的队列,因为SynchronousQuene内部最多只能包含一个元素(也可认为只能包含0个元素,因为包含一个元素后没线程消费进程就会阻塞)。插入元素到队列的线程被阻塞,直到另一个线程从队列中获取了队列中存储的元素。同样,如果线程尝试获取元素并且当前不存在任何元素,则该线程将被阻塞,直到线程将元素插入队列。
public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
    	//创建一个SynchronousQueue队列
        SynchronousQueue s = new SynchronousQueue();
        //创建一个消费线程
        Thread t = new Thread() {
            @SneakyThrows
            @Override
            public void run() {
                s.take();	//消费SynchronousQueue元素
            }
        };
        t.start();		//必须开启在s.put("666");语句前面,等待SynchronousQueue插入元素,否则进程一直阻塞
        s.put("666");	
        t.join();	
        System.out.println(s.size());	//最后的结果永远是0,因为只有为null,才不会阻塞
    }
}
  1. PriorityBlockingQueue
    优先级的无界阻塞队列,优先级通过参数Comparator实现。

六:threadFactory 线程工厂

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等

七:handler 饱和(拒绝)策略

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,就会执行饱和(拒绝)策略,JAVA中提供了4中拒绝策略:

  1. AbortPolicy(默认)
public static class AbortPolicy implements RejectedExecutionHandler {
       
    public AbortPolicy() { }
    // 直接丢弃任务 然后抛出异常
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}
  1. CallerRunsPolicy
public static class CallerRunsPolicy implements RejectedExecutionHandler {
        
    public CallerRunsPolicy() { }
    // 判断线程池是否shutdown,则直接抛弃任务,否则执行调用者中被拒绝任务的run方法
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            r.run();
        }
    }
}
  1. DiscardOldestPolicy
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        
        public DiscardOldestPolicy() { }
        // 抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }
  1. DiscardPolicy
public static class DiscardPolicy implements RejectedExecutionHandler {
    public DiscardPolicy() { }
	// 直接丢弃任务,什么都不做
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {}
}

JAVA自带的四种线程池(Executors类)

一:newCachedThreadPool

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

底层:通过源码可以看出newCachedThreadPool是直接返回一个ThreadPoolExecutor,且相关参数为:

corePoolSize      	核心线程数  0
maximumPoolSize     最大线程数  Integer.MAX_VALUE
keepAliveTime     	空闲线程存活时间    60
unit              	空闲线程存活时间单位	SECONDS
workQueue         	工作队列 SynchronousQueue
threadFactory     	线程工厂(默认defaultThreadFactory)
handler           	处理饱和状态机制(默认AbortPolicy)

线程池解析:通过传入的参数,可以看出这是一个没有核心线程,最大线程数却是Integer.MAX_VALUE(可认为无限大)
当有新任务到来,则插入到SynchronousQueue中,由于SynchronousQueue是同步队列,因此会在池中寻找可用线程来执行,若有可以线程则执行,若没有可用线程则创建一个线程来执行该任务;若池中线程空闲时间超过指定大小,则该线程会被销毁。

适用场景:执行很多短期的任务

二:newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

底层:通过源码可以看出newFixedThreadPool是直接返回ThreadPoolExecutor实例,接收参数为所设定核心线程数量nThreads,且相关参数为:

corePoolSize      	核心线程数  nThreads
maximumPoolSize     最大线程数  nThreads
keepAliveTime     	空闲线程存活时间    0
unit              	空闲线程存活时间单位	MILLISECONDS
workQueue         	工作队列 LinkedBlockingQueue
threadFactory     	线程工厂(默认defaultThreadFactory)
handler           	处理饱和状态机制(默认AbortPolicy)

线程池解析:通过传入的参数,可以看出这是一个固定数量线程的线程池,且都是核心线程,说明存活时间是无限的。
对于多余的任务都放入无界的LinkedBlockingQueue队列中。
适用场景:执行长期任务

三:newScheduledThreadPool

//ScheduledThreadPoolExecutor 类的源码
//可以看到ScheduledThreadPoolExecutor 继承 ThreadPoolExecutor
public class ScheduledThreadPoolExecutor 
		extends ThreadPoolExecutor
        implements ScheduledExecutorService

// Executors 类的源码
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
		//调用下面的代码
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

//ScheduledThreadPoolExecutor 类的源码
public ScheduledThreadPoolExecutor(int corePoolSize) {
		//调用父类(ThreadPoolExecutor)的构造器
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
    

底层:通过源码可以看出newScheduledThreadPool是返回ScheduledThreadPoolExecutor封装的ThreadPoolExecutor,接收参数为所设定核心线程数量corePoolSize,DelayedWorkQueue是ScheduledThreadPoolExecutor 静态内部类implement BlockingQueue,且相关参数为:

corePoolSize      	核心线程数  corePoolSize
maximumPoolSize     最大线程数  Integer.MAX_VALUE
keepAliveTime     	空闲线程存活时间    0
unit              	空闲线程存活时间单位	MILLISECONDS
workQueue         	工作队列 DelayedWorkQueue
threadFactory     	线程工厂(默认defaultThreadFactory)
handler           	处理饱和状态机制(默认AbortPolicy)

线程池解析:通过传入的参数,可以看出这是一个无限数量线程的线程池,核心线程存活时间是无限的,
对于keepAliveTime是0,maximumPoolSize设置为 Integer.MAX_VALUE
如果所有线程均处于繁忙状态,对于新任务会进入DelayedWorkQueue队列中,如果队列满了,
就会创建新的线程来执行,执行完,立马销毁。
DelayedWorkQueue是一个会将任务的延时时间进行排序,延时时间少的任务首先被获取的队列
适用场景:执行周期性任务

四:newSingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

底层:通过源码可以看出newSingleThreadExecutor是返回FinalizableDelegatedExecutorService封装的ThreadPoolExecutor,
且相关参数为:

corePoolSize      	核心线程数  1
maximumPoolSize     最大线程数  1
keepAliveTime     	空闲线程存活时间    0
unit              	空闲线程存活时间单位	MILLISECONDS
workQueue         	工作队列 LinkedBlockingQueue
threadFactory     	线程工厂(默认defaultThreadFactory)
handler           	处理饱和状态机制(默认AbortPolicy)

线程池解析:通过传入的参数,可以看出这是一个只有一个线程的线程池,且存活时间是无限的,工作队列是无界的。
任何任务请求都将放进LinkedBlockingQueue队列里,等待一个线程一个一个取出来执行。
适用场景:一个任务一个任务执行的场景

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值