10. 线程池

news/2024/5/20 7:18:57 标签: java, 线程, 多线程, juc, 线程池

连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用

线程(英语:thread pool)一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度

特点:

    降低资源消耗: 通过重复利用已创建的线程降低线程创建和销毁造成的销耗。
    提高响应速度: 当任务到达时,任务可以不需要等待线程创建就能立即执行。
    提高线程的可管理性: 线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

具体架构:
Java 中的线程池是通过 Executor 框架实现的,该框架中用到了 Executor,Executors,ExecutorService,ThreadPoolExecutor 这几个类

 

 说明:Executors为工具类,I为接口类,C为实现类

10.1 种类与创建

  • Executors.newFixedThreadPool(int)一池N线程
java">ExecutorService threadPool1 = Executors.newFixedThreadPool(5); //5个窗口

    Executors.newSingleThreadExecutor()一池一线程

java"> ExecutorService threadPool2 = Executors.newSingleThreadExecutor(); //一个窗口

  Executors.newCachedThreadPool()一池可扩容根据需求创建线程

java"> ExecutorService threadPool3 = Executors.newCachedThreadPool();

执行线程execute()
关闭线程shutdown()

void execute(Runnable command);参数为Runnable接口类,可以通过设置lambda

具体案例代码案例

java">//演示线程池三种常用分类
public class ThreadPoolDemo1 {
    public static void main(String[] args) {
        //一池五线程
        ExecutorService threadPool1 = Executors.newFixedThreadPool(5); //5个窗口
        //一池一线程
        ExecutorService threadPool2 = Executors.newSingleThreadExecutor(); //一个窗口
        //一池可扩容线程
        ExecutorService threadPool3 = Executors.newCachedThreadPool();
        //10个顾客请求
        try {
            for (int i = 1; i <=10; i++) {
                //执行
                threadPool3.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" 办理业务");
                });
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            //关闭
            threadPool3.shutdown();
        }
    }
}

10.2 底层原理

通过查看上面三种方式创建对象的类源代码
都有new ThreadPoolExecutor  具体查看该类的源代码,涉及七个参数

java">public ThreadPoolExecutor(int corePoolSize,
                         int maximumPoolSize,
                         long keepAliveTime,
                         TimeUnit unit,
                         BlockingQueue<Runnable> workQueue,
                         ThreadFactory threadFactory,
                         RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
      maximumPoolSize <= 0 ||
      maximumPoolSize < corePoolSize ||
     keepAliveTime < 0)
      throw new IllegalArgumentException();
      if (workQueue == null || threadFactory == null || handler == null)
         throw new NullPointerException();
       this.corePoolSize = corePoolSize;
       this.maximumPoolSize = maximumPoolSize;
       this.workQueue = workQueue;
       this.keepAliveTime = unit.toNanos(keepAliveTime);
       this.threadFactory = threadFactory;
       this.handler = handler;
}

具体代码中的七个参数讲解:
int corePoolSize, 常驻线程数量(核心)
int maximumPoolSize,最大线程数量
long keepAliveTime,TimeUnit unit,线程存活时间
BlockingQueue<Runnable> workQueue,阻塞队列(排队的线程放入)
ThreadFactory threadFactory,线程工厂,用于创建线程
RejectedExecutionHandler handler拒绝测试(线程满了)

具体工作流程是:

    在执行创建对象的时候不会创建线程
    创建线程的时候execute()才会创建
    先到常驻线程,满了之后再到阻塞队列进行等待,阻塞队列满了之后,在往外扩容线程,扩容线程不能大于最大线程数。大于最大线程数和阻塞队列之和后,会执行拒绝策略。

阻塞队列为3,常驻线程数2,最大线程数5

具体的拒绝策略有:

  1. 抛异常
  2. 谁调用找谁
  3. 抛弃最久执行当前
  4. 不理不问

10.3 自定义线程

实际在开发中不允许使用Executors创建,而是通过ThreadPoolExecutor的方式,规避资源耗尽风险

java">ExecutorService threadPool = new ThreadPoolExecutor(
        2,
        5,
        2L,
        TimeUnit.SECONDS,
        new ArrayBlockingQueue<>(3),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy()
);

其他都同理,只是调用ThreadPoolExecutor类,自定义参数

java">//自定义线程池创建  完整演示
public class ThreadPoolDemo2 {
    public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                2L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );

        //10个顾客请求
        try {
            for (int i = 1; i <=10; i++) {
                //执行
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" 办理业务");
                });
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            //关闭
            threadPool.shutdown();
        }
    }
}


http://www.niftyadmin.cn/n/1712916.html

相关文章

数据结构———插入排序(希尔排序,折半插入,直接插入)

排序 直接插入排序 直接插入排序。对于少量元素的排序&#xff0c;它是一个有效的算法 。插入排序是一种最简单的排序方法&#xff0c;它的基本思想是将一个记录插入到已经排好序的有序表中&#xff0c;从而一个新的、记录数增1的有序表。在其实现过程使用双层循环&#xff0…

11. Fork与Join分支

将一个大的任务拆分成多个子任务进行并行处理&#xff0c;最后将子任务结果合并成最后的计算结果 该算法相当于递归&#xff0c;且是二分查找思路 八种基本排序问题 &#xff08;第六篇 归并排序&#xff09;图文详解_想成为大神说32的博客-CSDN博客 class Fibonacci extends…

数据结构——交换排序(冒泡排序和快速排序。)

交换排序 所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置&#xff0c;交换排序的特点是&#xff1a;将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 冒泡排序 1、比较相邻的元素。如果第一个比第…

12. 异步回调

CompletableFuture 在 Java 里面被用于异步编程&#xff0c;异步通常意味着非阻塞&#xff0c;可以使得我们的任务单独运行在与主线程分离的其他线程中&#xff0c;并且通过回调可以在主线程中得到异步任务的执行状态&#xff0c;是否完成&#xff0c;和是否异常等信息 类中的…

数据结构————哈希表的实现(语言)

哈希表 散列表&#xff08;Hash table&#xff0c;也叫哈希表&#xff09;&#xff0c;是根据关键码值(Key value)而直接进行访问的数据结构。也就是说&#xff0c;它通过把关键码值映射到表中一个位置来访问记录&#xff0c;以加快查找的速度。这个映射函数叫做散列函数&…

排序算法(对三个数进行排序三指针)

思路 采用三个指针 1&#xff09;头指针之前都是第一个数 2&#xff09;尾指针之后都是地三个数 3&#xff09;两个指针之间是第二个数 看一下例子&#xff1a; 例如对{1&#xff0c;0&#xff0c;0&#xff0c;2&#xff0c;2&#xff0c;1&#xff0c;0&#xff0c;2}进行排…

Java后端对 前端的学习了解 ,基础知识和各框架功能发展概述,以及了解前后端的分离史

Bootstrap可视化布局系统 (bootcss.com) 这是一个创建可视化布局的生成前端代码&#xff0c;根据你的需要&#xff0c;拖到按钮&#xff0c;然后就可以复制生成的代码 提示&#xff1a;学习一门技术&#xff0c;最好的方式就是官方文档&#xff0c;可以看完视频&#xff0c;笔…

数据结构————栈(力扣)

栈 来源&#xff1a;1381. 设计一个支持增量操作的栈 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode-cn.com/problems/design-a-stack-with-increment-operation typedef struct { int *a; //用数组表示一个栈int size; //…