java线程池介绍

本次针对http请求线程池使用介绍
线程池应用场景:1.当后台一个功能需要调用几个http接口(各个接口不相互依赖),如果不用线程池(同步请求),那么一个接一个地调用,耗时比较长,所以大部分时间花在等待接口的处理上,如果使用线程池(异步请求),那么几个http接口调用可以同时进行,并缩短了等待时间(一般中大型公司会使用到该场景,一般用户触碰到某个功能没有反应就是会影响用户体验)。2.当HTTP线程池
线程池重点:每一次http请求会创建一个线程,每次创建和销毁一个线程都需要时间,如果大量创建线程那么会让服务器资源耗尽等危险(尤其是会员活跃平台),那么线程池作用就是线程重复使用,而且必须对线程池设置超时时间(unit)
实例代码如下:
 

//用线程池发送请求
ExecutorService executor = Executors.newFixedThreadPool(3);

//风控
FengKong fengKong = new FengKong(symptom);
Thread t1 = new Thread(fengKong);
executor.execute(t1);

//人脸识别
FaceKnow faceKnow= new FaceKnow(facePath);
Thread t2 = new Thread(faceKnow);
executor.execute(t2);

//身份认证
IdAuth  idAuth= new IdAuth(tonguePath);
Thread t3 = new Thread(idAuth);
executor.execute(t3);

//等待线程执行完毕,每一个task都发送了请求并获取结果解析后放到task中的某个变量中,执行完后就可以获得这些变量来获得所要的结果
executor.shutdown();
while(!executor.isTerminated()) {
}
如果返回每个线程池处理的数据,要使用Callable、Future的两种使用方式
参考如下:https://blog.csdn.net/zhaominpro/article/details/78054046 也可以参考自己的文章
java多线程基础_感冒石头的博客-CSDN博客

常用几种线程池介绍
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

(1).newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程
//为了体验到复用线程效果,每一个线程进行100毫秒*n休眠

public static void main(String[] args) {
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        try {
            Thread.sleep(index * 100);
        } catch (Exception e) {
            e.printStackTrace();
        }

        cachedThreadPool.execute(new Runnable() {

            @Override
            public void run() {
                System.out.println(index+"当前线程"+Thread.currentThread().getName());
            }
        });
    }
}

结果如下:
0当前线程pool-1-thread-1
1当前线程pool-1-thread-1
2当前线程pool-1-thread-1
3当前线程pool-1-thread-1
4当前线程pool-1-thread-1
5当前线程pool-1-thread-1
6当前线程pool-1-thread-1
7当前线程pool-1-thread-1
8当前线程pool-1-thread-1
9当前线程pool-1-thread-1

(2). newFixedThreadPool  创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
线程池中设置数量为3个,那么只会有三个线程执行10条数据
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
    final int index = i;
    fixedThreadPool.execute(new Runnable() {
        public void run() {
            try {
                Thread.sleep(2000);
                System.out.println(index+"当前线程"+Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}

结果如下:
0当前线程pool-1-thread-1
1当前线程pool-1-thread-2
2当前线程pool-1-thread-3
3当前线程pool-1-thread-1
4当前线程pool-1-thread-2
5当前线程pool-1-thread-3
6当前线程pool-1-thread-1
7当前线程pool-1-thread-2
8当前线程pool-1-thread-3
9当前线程pool-1-thread-1

(3).newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行
线程池延迟3秒后执行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
    public void run() {
        System.out.println("延迟3秒后执行");
    }
}, 3, TimeUnit.SECONDS);

(4).newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
下面是按照顺序执行FIFO(一般情况下多线程index是乱的,该线程池保证了按照顺序执行)
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
    final int index = i;
    singleThreadExecutor.execute(new Runnable() {
        public void run() {
            try {
                System.out.println("--index--"+index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}

结果如下:
--index--0
--index--1
--index--2
--index--3
--index--4
--index--5
--index--6
--index--7
--index--8
--index--9


重点
1、底层结构实现原理:是基于阻塞队列实现

newCachedThreadPool 默认是用SynchronousQueue队列实现
newFixedThreadPool 默认是用LinkedBlockingQueue队列实现
newScheduledThreadPool默认是用DelayedWorkQueue队列实现
newSingleThreadExecutor默认是用LinkedBlockingQueue队列实现


2、自己构建一个线程池参数有哪些
public ThreadPoolExecutor(int corePoolSize,   int maximumPoolSize,   long keepAliveTime,   TimeUnit unit,
            BlockingQueue<Runnable> workQueue);

1、corePoolSize: 核心线程数
2、maximumPoolSize:最大支持线程数
3、keepAliveTime :当线程空闲超过一段时间,线程池会判断:运行的线程数大于corePoolSize,线程被停掉
4、TimeUnit :过期时间单位
5、workQueue:使用什么队列

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

3、底层实现原理:首先调用executor()执行任务,进入线程池,此时线程数还未超过corePoolSize,当线程数超过corePoolSize时,线程会进入阻塞队列等待,当阻塞队列的线程存到一定数量时,线程池会扩容,但不会超过最大线程数,maximumPoolSize,当线程数量超过最大线程数时,线程池会启动拒绝策略,来保证任务正常进行,当任务线程数越来越少时,会逐渐恢复到corePoolSize

线程池四种拒绝策略:
AbortPolicy 直接抛出RejectedExecutionExeception异常来阻止系统正常运行   默认策略
CallerRunsPolicy 将任务回退到调用者
DisOldestPolicy 丢掉等待最久的任务‘
DisCardPolicy 直接丢弃任务
这四种拒绝策略均实现的RejectedExecutionHandler接口

4、线程存活问题
newCachedThreadPool 默认启用一个线程。默认存活时间60s,如果超过60s第一个线程销毁,重新创建一个新的线程
newSingleThreadExecutor:默认启用一个线程。不过期,自始至终只有一个线程来执行任务
newFixedThreadPool :设置固定核心线程数,有多个核心线程执行任务
newScheduledThreadPool:设置固定核心线程数,有多个核心线程执行任务
可参考业务地址:
Executors.newCachedThreadPool的底层源码浅析_明明如月的技术博客-CSDN博客_newcachedthreadpool

Java线程池如何合理配置核心线程数?

第一步:先看下机器的CPU核数,然后再设定具体参数

CPU核数=Runtime.getRuntime().availableProcessors()

System.out.println(Runtime.getRuntime().availableProcessors());

第二步:分析下线程池处理的程序是CPU密集型,还是IO密集型

CPU 密集型:核心线程数 = CPU核数 + 1

IO 密集型:核心线程数 = CPU核数 * 2

注意:IO密集型 (某大厂实战经验)
核心线程数 = CPU核数 / (1 - 阻塞系数)
例如阻塞系数为0.8 ,CPU核数为 4 ,则核心线程数为 20
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值