Java线程池

线程池

线程池能够提高资源的利用率,加快响应速度,也是池化思想的一种,便于对线程的管理。

1.线程池的组成

ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

corePoolSize:核心线程数量。当有任务执行的时候,如果当前执行数量小于核心线程数量,会创建线程执行任务。

maximumPoolSize:最大线程数量。当当前执行线程数量等于核心线程数量时候,并且阻塞队列已经满的时候,会判断当前线程数量是否大于最大线程数量,如果小于的话,则会创建线程完成任务的执行;如果大于的话,则根据拒绝策略完成任务的丢弃;

keepAliveTime:空闲线程存活时间。也就是说当核心线程数量为10,最大线程数量为30,当前执行的线程20,但是过了会任务少了,执行的线程也就少了,如果少于10的时候,从最大线程数量中借来的线程数量会处于空闲状态,keepAliveTime指的是隔多久空闲的线程被回收。

unit:空闲线程存活时间的单位。可以为时,分,秒等,具体单位可以参考TimeUnit枚举类。

workQueue:工作队列。作用是如果当前的线程数量等于核心线程数量的时候,会将待处理的任务放到工作队列中。工作队列分为:
工作队列

工作队列说明
LinkedBlockingQueue基于链表的阻塞队列,使用ReentrantLock保证多线程操作下的安全性。
ArrayBlockingQueue基于数组实现的阻塞队列,出入队列按照FIFO方式,有大小限制
PriorityBlockingQueue基于最小二叉堆实现,无界阻塞队列(默认初始化容量为11)
SynchronousQueue基于公平的队列和非公平的堆栈实现(默认为堆栈)。队列不存储元素,插入操纵须在take后才能操作。

threadFactory:线程工厂,用于创建新的线程。默认使用Executors.defaultThreadFactory()创建工厂。

handler:拒绝执行处理器,当处理不了任务的时候,使用特定的拒绝策略拒绝任务。拒绝策略分为:

在这里插入图片描述
七大参数(以足球的角度解释参数)
核心线程数量是前锋,来任务就创建线程处理,这里涉及了一个全局锁!
最大线程数量是前锋+后卫,当中峰装不下了,后卫完成支援
阻塞队列相当于中锋,装任务用的。分为有界和无界。
拒绝策略是守门员:都支撑不住了,我要拒绝你进入了。
线程工厂:球员生产中心。
keepAliveTime是不需要那么多人了,截止多长时间前锋或者后卫就需要休息了,随机选取前锋和后卫休息。
Unit 是keepAliveTime的单位。

拒绝策略说明
DiscardPolicy执行当前还没执行完毕的任务,有新的任务直接丢弃
DiscardOldestPolicy执行当前还没执行的任务,淘汰工作队列中时间最久的任务,给新任务腾地方
AbortPolicy当处理不了的时候,直接抛出异常(默认策略)
CallerRunsPolicy谁提交任务是谁执行。能够保证任务执行的可靠性。

2.线程池的分类

常用的线程池一共分为以下四类

newCachedThreadPool :可缓存的线程池。可灵活回收空闲线程,若无可回收,否则新建线程。操作不当容易出现OOM(线程最大并发数不可控制)
newFixedThreadPool:固定大小的线程池。可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool : 定时调度的线程池。支持定时及周期性任务执行。
newSingleThreadExecutor :单个线程执行的线程池。它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果当前执行的线程挂了,会创建一个线程继续执行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MsKkGbxv-1689946206548)(C:\Users\86136\AppData\Roaming\Typora\typora-user-images\image-20230721210702805.png)]

3.线程池执行的状态

在这里插入图片描述

4.线程池execute和submit方法的异同

:二者都是使用线程池执行任务的启动方法。

:execute方法无返回值,submit有返回值;submit不但能够执行runnable类型接口的任务,还能够执行Callable接口的任务。

5.当来任务的时候,线程池处理流程。

分为三步:
1)先判断当前线程数量是否超过核心线程数量,如果没有超过,则创建线程进行处理任务,这里涉及一个获取全局锁的问题。如果超过了走第二步。
2)判断当前阻塞队列是否已经满了,如果没有满的话,则放入阻塞队列里。如果满了走第三步。
3)判断当前线程数量是否超过了最大线程数量,如果没有的话,创建线程进行处理,如果超过了走拒绝策略。

6.使用调度线程池完成任务的定时调度。

每周周四定时18点完成任务的执行

package com.wzt.ThreadPool;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.*;

/**
 * 定时任务执行每周的周四下午6点执行
 */
public class scheduledThreadPool {
    public static void main(String[] args) {
        //不推荐使用Executors.newScheduledThreadPool();
        // ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
        ScheduledThreadPoolExecutor poolExecutor=new ScheduledThreadPoolExecutor(1);
        //获取当前时间
        LocalDateTime now=LocalDateTime.now();
        //获取周四时间
        LocalDateTime time=now.withHour(18).withMinute(0).withSecond(0).withNano(0).with(DayOfWeek.THURSDAY);
        //如果当前时间大于周四的时间差
        if(now.compareTo(time)>0){
            time=time.plusWeeks(1);
        }
        System.out.println("当前时间为"+now);
        System.out.println("下一个周四为"+time);
       //initailDelay的含义表示为距离当前时间为多少
       long initailDelay= Duration.between(now,time).toMillis();
       //period一周的间隔时间
        long period=1000*60*60*24*7;
        System.out.println("距离抢购时间还有:"+Duration.between(now,time).toHours()+"小时");
        poolExecutor.scheduleAtFixedRate(()->{
            System.out.println("running...");
        },initailDelay,period, TimeUnit.MILLISECONDS);
    }
}

线程池的应用

1.建议设置阻塞队列为有界队列。
2.建议自定义线程池,如果使用Executors创建的会出现oom问题。
3.针对于CPU密集型任务使用核心线程数量为CPU+1,IO密集型使用2*CPU的个数。
4.可以使用Runtime.getRuntime().availableProcessors()获取电脑的核心数。
Java并发编程艺术最后一章
参考资料:【https://www.bilibili.com/video/BV16J411h7Rd?p=228&vd_source=d21f6cadf3168d41bf967c271d63a9fb】

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值