java线程池

一、ThreadPoolExecutor

1.1 常用参数

corePoolSize:核心线程数
maximumPoolSize:线程池最大允许线程数
workQueue:任务队列
threadFactory:线程创建工厂
handler: 任务拒绝策
keepAliveTime, unit:等待时长

1.2 执行流程

在这里插入图片描述

  • 首先判断线程数是否大于corePoolSize
  • 否,threadFactory创建新线程执行任务
  • 是,判断线程数是否大于maximumPoolSize?
  • 是,handler执行拒绝策略
  • 否,检查队列是否已经满了
  • 否,放入队列中,等待线程执行
  • 是,创建新的队列,放到新的队列中

注意:
当线程数超过corePoolSize,并且超过的线程处于空闲状态,则超过Alivetime,空闲线程就会被中资。

1.3 workQueue的实现

  • SynchronouseQueue
    这是一个空队列,不会保存提交的task
  • ArrayBlockingQueue
    数组实现的队列,可以指定数组的长度
  • LinkedBlockingQueue
    数组实现的队列,也可以指定队列的长度

1.4 RejectedExecutionHandler的实现

  • AbortPolicy
    直接抛出RejectedExecutionException,这是线程池中的默认实现
  • DiscardPolicy
    什么都不做
  • DiscardOldestPolicy
    丢弃workQueue队头任务,加入新任务
  • CallerRunsPolicy
    直接在调用者的线程执行任务

1.5 Execute方法

 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);
    }
  1. 判断Runnable是否为空,为空,抛出空指针异常
  2. 获取线程池中线程数量,如果小于corePoolSize,则添加新线程执行任务,添加成功返回
  3. 添加失败,则重新获取线程数,如果线程数大于corePoolSize,则将任务添加到任务队列中(前提是线程池未关闭)。其他,跳转到6.
    4.判断线程池是否关闭,如果线程池关闭,则移除任务,并执行拒绝策略。
  4. 如果没关闭,意味着检查通过,则新建线程去执行
    6.尝试着再将任务添加到任务队列,失败,执行拒绝策略。

1.6 线程池实战

package com.example.seckilldemo.Test;


import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.SneakyThrows;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolTest {
    public static void main(String[] args) {
        //直接丢弃
        new ThreadPoolExecutor.DiscardPolicy();
        //拒绝策略
        new ThreadPoolExecutor.AbortPolicy();
        //触发拒绝策略,线程池未关闭,丢弃任务队列最久的,即队列头的任务,将任务加入队列
        new ThreadPoolExecutor.DiscardOldestPolicy();
        //触发拒绝策略,线程池未关闭,使用调用者线程执行任务
        new ThreadPoolExecutor.CallerRunsPolicy();
        LinkedBlockingDeque<Runnable> work = new LinkedBlockingDeque<>(5);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 5, 5, TimeUnit.SECONDS, work, new ThreadFactoryBuilder()
                .setNameFormat("thread-自定义线程名-runner-%d").build(),new ThreadPoolExecutor.AbortPolicy());
        for (int i = 0; i < 13; i++) {
            threadPoolExecutor.submit(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName()+"finish");
                }
            });
        }
       threadPoolExecutor.shutdown();
    }
}

二、ScheduledExecutorService

1.1 public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)

用于定时执行任务,延迟的时间为delay*unit,它返回一个ScheduledFuture对象用于获取执行结果或者剩余延时,调用Future.get()方法将阻塞当前线程最后返回null。

1.2 public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit);

同上,不同的是,调用Future.get()方法将返回执行的结果,而不是null。

1.3 public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period,TimeUnit unit);

重复执行任务command,第一次执行时间为initialDelay延迟后,以后的执行时间将在initialDelay + period * n,unit代表时间单位,值得注意的是,如果某次执行出现异常,后面该任务就不会再执行。或者通过返回对象Future手动取消,后面也将不再执行。

1.4 public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay, TimeUnit unit);

效果同上,不同点:如果command耗时为 y,则上面的计算公式为initialDelay + period * n + y,也就是说,它的定时时间会加上任务耗时,而上面的方法则是一个固定的频率,不会算上任务执行时间!

三、ScheduledThreadPoolExecutor

3.1 继承关系

ScheduledThreadPoolExecutor继承自ThreadPoolExecutor类,实现了ScheduledExecutorService接口,上面均已经分析。

3.2 特点

最大线程数为最大值,任务队列是默认的。

四、线程池

4.1 优点

  • 减少创建和销毁线程带来的时间,资源消耗,而且创建好的线程可以重复利用
  • 减少因创建线程带来的时间等待,可以直接使用线程
  • 可以整体的管理线程

4.2 执行流程

  • 判断当前核心线程池的线程是不是都在执行任务,不是,则新建工作线程去执行任务(需要获得全局锁)
  • 是,则判断任务队列是不是满了,不是,将任务添加进任务队列
  • 是,判断线程池中的线程是不是已经满了,不是,则新建线程去处理(获得全局锁)
  • 是,交给饱和策略去处理

4.3 工作线程

线程池创建的时候,会将线程封装成工作线程,工作线程执行完自己的任务后,会反复从线程队列中取出任务来执行。

4.4 参数

4.4.1 corePoolSize

核心线程数,调用prestartAllCoreThreads()方法,线程池会提前创建并启动所有的基本线程。

4.4.2 runnableTaskQueue(任务队列)

  • ArryaBlockingQueue
    基于数组的有界队列,按照先进先出原则对与元素进行排序。
  • LinkedBlockingQueue
    一个基于链表结构的阻塞队列,按照FIFO排序元素
  • SynchronouseQueue
    一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态。
  • PriorityQueue
    具有有优先级的无线阻塞队列

4.4.3 maximumPoolSize

线程池最大容量,如果使用无界的队列就没有什么效果了

4.4.4 ThreadFactory

设置创建线程的工厂,通过工厂给线程进行命名。

4.4.5 ExecutionHandler

  • AbortPolicy
    直接抛出异常
  • CallerRunsPolicy
    只用调用者所在线程来运行任务
  • DiscardOldestPolicy
    丢弃队列里最近的一个任务,并执行当前任务
  • DiscardPolicu
    不处理,丢弃掉

4.4.6 keepAliveTime

工作线程空闲后,保存存活的时间。

4.4.7 TimeUnit

线程活动保持时间的单位

4.5 向线程池提交任务

  • Execute()
    用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功
  • Submit()
    submit用于提交需要返回值的任务,线程池需要返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get方法获取返回值。get方法会阻塞当前线程直到任务完成。

4.6 关闭线程池

逐个遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的线程永远不会停止。shutdownNow首先将线程池的状态设置成stop,然后尝试去关闭所有的线程,shutdown将线程的状态设置成SHUTDOWN。然后中断没有正在执行任务的线程。
只要调用了其中之一的方法,isShutdown方法就会返回true,当所有任务都关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。
任务不一定执行完,则调用shutdownNow方法。

4.7 合理的配置线程池

4.7.1 首先分析任务的性质

任务的性质:cpu密集型任务,io密集型任务和混合型任务。
任务的优先级:高中低
任务的执行时间:长中段
任务的依赖性:是否依赖其他资源

4.8 线程池的监控

taskCount:线程池需要执行的任务数量
completedTaskCount:线程池在运行过程中已经完成的线程数量
largestPoolSize:线程池曾创建的最大线程的数量
getPoolSize:线程池的线程数量
getActiveCoutn:获取活动的线程数

五、任务队列

5.1 ArrayBlockingQueue

是一个基于数组结构的有界队列,此队列按FIFO(先进先出)原则对元素进行排序

5.2 LinkedBlockingQueue

一个基于链表的无界队列,此队列按照FIFO排序元素,吞吐量通常要高于ArrayBlockingQueue,静态工厂方法Executors.newFixedThreadPool()使用了这个队列。

5.3 SynchronousQueue

一个不存储元素的有界队列,每个插入操作必须等到另一个线程的移除操作,否则插入操作一直处于阻塞状态。吞吐量高于LinkedlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。

5.4 PriorityBlockingQueue

一个具有优先级的无限阻塞队列。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值