Java线程池理解与举例使用(详细) 您所在的位置:网站首页 java线程池设置多大 Java线程池理解与举例使用(详细)

Java线程池理解与举例使用(详细)

2023-10-17 14:56| 来源: 网络整理| 查看: 265

小聊: 线程池的概念还是很重要的,“池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。线程池、数据库连接池、Http连接池等等都是对这个思想的应用。”这句话评价的很到位。虽然它很常用但是占代码时间比例不多,容易忘记。本文稍微详细介绍一下线程池的整体知识并举例使用,便于回忆。

1. 了解线程池 2. Executors 线程池2.1. 常见线程池种类2.2. 常用线程池方法2.3. Executors 使用说明2.4. Executors创建线程池使用示例(工具类) 3. ThreadPoolExecutor 线程池 3.1. 了解ThreadPoolExecutor 3.2. ThreadPoolExecutor 构造函数源码3.3. 线程池工作原理流程(重要)3.4. ThreadPoolExecutor 线程池使用示例 4. 使用线程池的好处随笔 1. 了解线程池

如果想让线程池执行任务的话需要实现的 Runnable 接口或 Callable 接口。 Runnable 接口或 Callable 接口实现类都可以被ThreadPoolExecutor 或 ScheduledThreadPoolExecutor 执行。两者区别: Runnable 接口不会返回结果, Callable 接口可以返回结果。

Java里面线程池的顶级接口是 java.util.concurrent.Executor ,但是严格意义上讲 Executor 并不是一个线程池,而只是一个执行线程的工具类。真正的线程池接口是 java.util.concurrent.ExecutorService 。

2. Executors 线程池 2.1. 常见线程池种类 线程池名称描述newSingleThreadExecutor()创建一个单线程的线程池,此线程池保证所有任务的执行顺序按照任务的提交顺序执行。newFixedThreadPool(int nThreads)nThreads:线程数。创建固定大小的线程池,每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。newCachedThreadPool()创建一个可缓存的线程池,此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。newScheduledThreadPool(int corePoolSize)创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求。 2.2. 常用线程池方法 方法解释Future submit(Runnable task)获取线程池中的某一个线程对象,并执行。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功。( Future接口:用来记录线程任务执行完毕后产生的结果。)public void execute(Runnable command)用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否。public void shutdown()注意:Executors类包含一组方法,它们可以将其他一些常见的类闭包对象,例如,java.security.PrivilegedAction转换为Callable表单,以便提交它们。销毁或关闭线程池 2.3. Executors 使用说明

要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在 java.util.concurrent.Executors 线程工厂类里面提供了一些静态工厂,生成一些常用的线程池。官方建议使用 Executors 工程类来创建线程池对象。

但是《阿里巴巴Java开发手册》中却强制线程池不允许使用 Executors,而是使用 ThreadPoolExecutor ,下文详细介绍。

2.4. Executors创建线程池使用示例(工具类) class MyPool implements Runnable { @Override public void run() { System.out.println("线程" + Thread.currentThread().getName() + "的run方法正在运行"); } } public class Demo { public static void main(String[] args) { // 创建一个固定大小的线程池 ExecutorService es = Executors.newFixedThreadPool(2); MyPool pool = new MyPool(); es.submit(pool); es.submit(pool); es.submit(pool); // 关闭线程池 es.shutdown(); } } 输出 线程pool-1-thread-1的run方法正在运行 线程pool-1-thread-2的run方法正在运行 线程pool-1-thread-1的run方法正在运行 3. ThreadPoolExecutor 线程池 3.1. 了解ThreadPoolExecutor

《阿里巴巴Java开发手册》中强制线程池不允许使用 Executors 工具类去创建,因为方法参数没有或只有一个,难以满足场景需求。而是通过 ThreadPoolExecutor 的方式,提供的入参很多,可定制线程池。这样的处理方式可以加明确线程池的运行规则,规避资源耗尽的风险。

Executors.xxxxxx 返回线程池对象的弊端如下: newFixedThreadPool 和 newSingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致 OOM(内存不足)。 newCachedThreadPool 和 newScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致 OOM。

3.2. ThreadPoolExecutor 构造函数源码 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize System.out.println("线程" + Thread.currentThread().getName() + "的run方法Start"); working(); System.out.println("线程" + Thread.currentThread().getName() + "的run方法End"); } // 模拟线程执行耗时5s private void working() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * @Author 白忆宇 */ public class Demo02 { private static final int CORE_POOL_SIZE = 5; // 核心线程数 private static final int MAX_POOL_SIZE = 10; // 最大线程数 private static final Long KEEP_ALIVE_TIME = 1L; // 等待新任务的最大时间(1s) private static final int QUEUE_CAPACITY = 50; // 任务队列为ArrayBlockingQueue,容量50; public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, // 等待时间单位 new ArrayBlockingQueue(QUEUE_CAPACITY), // 使用初始固定容量的队列 Executors.defaultThreadFactory(), // 线程工厂类(默认值) new ThreadPoolExecutor.CallerRunsPolicy()); // 饱和策略 // 开启10个线程 for (int i = 0; i } System.out.println("多线程执行完毕"); } } // 输出 线程pool-1-thread-1的run方法Start 线程pool-1-thread-3的run方法Start 线程pool-1-thread-4的run方法Start 线程pool-1-thread-2的run方法Start 线程pool-1-thread-5的run方法Start 线程pool-1-thread-4的run方法End 线程pool-1-thread-5的run方法End 线程pool-1-thread-2的run方法End 线程pool-1-thread-2的run方法Start 线程pool-1-thread-1的run方法End 线程pool-1-thread-3的run方法End 线程pool-1-thread-1的run方法Start 线程pool-1-thread-5的run方法Start 线程pool-1-thread-4的run方法Start 线程pool-1-thread-3的run方法Start 线程pool-1-thread-4的run方法End 线程pool-1-thread-1的run方法End 线程pool-1-thread-2的run方法End 线程pool-1-thread-5的run方法End 线程pool-1-thread-3的run方法End 多线程执行完毕

输出过程解释: 因为设置了核心线程数为5,会先同时打印5行,5秒执行后再打印同时10行(结束的五个线程和新开始的五个线程),最后5秒执行后再同时打印5行,结束后5个线程。总共20行,10个线程的开始和结束。

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

在这里插入图片描述



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有