Java线程池必知必会知识点总结

Java线程池必知必会知识点总结

在并发编程中,线程池是一种重要的资源管理方式。线程池可以管理和执行多个线程,从而提高程序的性能和效率,同时还能避免线程创建和销毁的开销。

本文将介绍Java线程池的相关知识点,包括线程池的基本概念、实现原理、使用方法和注意事项。

线程池的基本概念

Java中的线程池主要有两种实现方式:FixedThreadPool和CachedThreadPool。

  • FixedThreadPool指定池大小,当需要执行任务时如果池中没有可用线程,则任务会被阻塞,直到有足够的可用线程执行。
  • CachedThreadPool不指定池大小,线程池会尽量使用空闲线程执行任务,如果没有空闲线程就会创建新线程执行任务,如果线程空闲时间超过指定时间(默认60秒)则被回收。

线程池的核心参数包括以下几个:

  • corePoolSize: 线程池核心线程数,即线程池中最少的线程数。
  • maximumPoolSize: 线程池最大线程数,即线程池中最多的线程数。
  • keepAliveTime: 空闲线程存活时间,即超过corePoolSize的线程的最大空闲时间,单位为毫秒。
  • TimeUnit: keepAliveTime的时间单位,可以是秒、分钟、小时等。
  • BlockingQueue: 等待队列,用于存放尚未执行的任务。

线程池的实现原理

Java线程池的实现原理主要是通过ThreadPoolExecutor类实现的。

ThreadPoolExecutor是线程池的核心类,它负责管理线程的创建、销毁、调度以及任务的执行。ThreadPoolExecutor的初始化需要传入上述核心参数,以及一个RejectedExecutionHandler对象。

RejectedExecutionHandler是一个回调处理接口,当线程池无法执行新的任务时,会调用该接口的rejectedExecution方法。Java中提供了一些实现了该接口的类,比如AbortPolicy、CallerRunsPolicy、DiscardPolicy和DiscardOldestPolicy。如果不传入RejectedExecutionHandler对象,则使用默认的AbortPolicy。

线程池的使用方法

使用Java线程池主要包括以下步骤:

  1. 创建一个ThreadPoolExecutor对象,指定核心参数和RejectedExecutionHandler对象。
  2. 使用ThreadPoolExecutor的submit方法提交任务,submit()方法会返回Future对象,可以通过该对象判断任务是否执行完成。
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 60L, TimeUnit.SECONDS,
        new LinkedBlockingQueue<Runnable>());
for (int i = 0; i < 10; i++) {
    executor.submit(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " is running");
        }
    });
}

上述代码创建了一个核心线程数为2,最大线程数为5的线程池,并往线程池中提交了10个任务。因为等待队列使用的是LinkedBlockingQueue,所以当线程池中有空闲线程时,会直接使用空闲线程执行任务。

  1. 关闭线程池。一般情况下,我们不需要手动调用ThreadPoolExecutor的shutdown方法关闭线程池,因为JVM会在程序退出时自动关闭线程池。但是如果需要手动关闭线程池,应该先调用ThreadPoolExecutor的shutdown方法,此时线程池会拒绝接受新任务,并尝试完成已经提交的任务。如果还有未完成的任务,这些任务会被等待完成,如果等待超时,则会强制中断还在运行的任务。
executor.shutdown();

线程池的注意事项

  • 最大线程数的设置需要考虑当前环境的硬件资源,比如CPU核数、内存大小等。
  • 使用线程池不能滥用,应该根据具体情况合理使用。
  • 对于执行时间较短的任务,可以使用CachedThreadPool,对于执行时间长的任务,可以使用FixedThreadPool。
  • 记得关闭线程池。

示例1:FixedThreadPool

ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
    executorService.submit(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " is running");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}
executorService.shutdown();

上面的代码创建了一个核心线程数为5的线程池,并提交了10个任务。因为线程池的核心线程数只有5,所以只创建了5个线程执行任务,其他任务则等待空闲线程执行。

运行结果如下:

pool-1-thread-1 is running
pool-1-thread-2 is running
pool-1-thread-4 is running
pool-1-thread-3 is running
pool-1-thread-5 is running
pool-1-thread-1 is running
pool-1-thread-2 is running
pool-1-thread-4 is running
pool-1-thread-3 is running
pool-1-thread-5 is running

可以看到,线程池中的5个线程依次执行了10个任务,每个任务执行1秒钟。

示例2:CachedThreadPool

ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
    executorService.submit(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " is running");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}
executorService.shutdown();

上面的代码创建了一个没有核心线程数限制的线程池,并提交了10个任务。因为线程池没有限制最大线程数,所以会根据任务的数量和执行时间来自动创建和回收线程。

运行结果如下:

pool-1-thread-2 is running
pool-1-thread-1 is running
pool-1-thread-3 is running
pool-1-thread-4 is running
pool-1-thread-5 is running
pool-1-thread-6 is running
pool-1-thread-7 is running
pool-1-thread-8 is running
pool-1-thread-10 is running
pool-1-thread-9 is running

可以看到,线程池中创建了10个线程,并且线程的创建和回收是自动的。每个任务执行1秒钟。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java线程池必知必会知识点总结 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • SpringMVC上传图片与访问

    SpringMVC上传图片与访问攻略 SpringMVC是一个非常流行的Java Web框架,它提供了很多方便的功能,包括文件上传和图片访问。在本文中,我们将详细讲解如何在SpringMVC中上传图片并访问它们。 上传图片 在Web应用程序中,文件上传是一个非常常见的需求。SpringMVC提供了很多方便的方式来处理文件上传,包括使用MultipartFil…

    Java 2023年5月18日
    00
  • JAVA多线程之方法 JOIN详解及实例代码

    JAVA多线程之方法 JOIN详解及实例代码 什么是JOIN方法? 在Java多线程中,Join方法是Thread类提供的一种方法。用于主线程等待子线程执行完毕后再执行,即实现主线程对于子线程的加入(join)操作。 JOIN方法的语法 在Java多线程中,join方法的语法如下: public final void join() throws Interr…

    Java 2023年5月18日
    00
  • 什么是内存溢出?

    以下是关于内存溢出的完整使用攻略: 什么是内存溢出? 内存溢出是指程序在申请内存时,没有足够的内存空间可供使用,导致程序无法正常运行。内存溢出是一种常见的程序错误,如果不及时处理,会导致程序崩溃或者系统崩溃。 以下是一个 C++ 中内存溢出的示例: void func() { *p = new int[1000000000000]; do something…

    Java 2023年5月12日
    00
  • java数字和中文算数验证码的实现

    下面将为你讲解如何实现“Java数字和中文算数验证码”的过程。 1. 实现思路 Java数字和中文算数验证码一般包括以下几个步骤: 生成算式表达式和结果 将算式表达式和结果转化为图片 将图片显示在界面上 验证用户输入的答案是否正确 2. 实现步骤 2.1 生成算式表达式和结果 算式表达式可以随机生成,常见的包括加减乘除四则运算,可以使用Java中的随机数生成…

    Java 2023年5月19日
    00
  • Java 如何同时返回多个不同类型

    实现 Java 同时返回多个不同类型的方法可以有多种,以下是三种可行的方案: 方案一:利用类封装多个返回值 在 Java 中,可以使用一个类封装多个返回值。通过定义一个类(比如下面的 Result 类),该类包含多个字段,每个字段表示一个要返回的值,然后在需要返回多个值的函数中,可以将这些值封装并返回一个 Result 类的实例。以下是实现过程的示例: pu…

    Java 2023年5月26日
    00
  • ES6知识点整理之模块化的应用详解

    关于“ES6知识点整理之模块化的应用详解”的完整攻略,以下是我的分享: 1. 概述 在ES6中,我们可以使用模块化来组织和管理代码,这也是ES6语法中比较重要的一个知识点。通过模块化,我们可以把一个大文件拆分成多个小文件,每个小文件只负责一个特定的功能,这样既方便代码的维护,也提高了代码的可读性和可复用性。 2. 模块化的基础语法 在ES6中,可以使用imp…

    Java 2023年5月26日
    00
  • 使用JSON.toJSONString格式化成json字符串时保留null属性

    使用JSON.toJSONString方法将Java对象转化为JSON字符串时,默认会将值为null的属性过滤掉。如果需要在生成的JSON字符串中保留null属性,可以通过设置输出时的SerializerFeature来实现。 具体步骤如下: 导入FastJSON库的依赖,示例代码如下: xml <dependency> <groupId&…

    Java 2023年5月26日
    00
  • 浅析Java自定义注解的用法

    接下来我会详细讲解“浅析Java自定义注解的用法”的完整攻略。 什么是Java自定义注解 Java自定义注解相对于内置的注解,可以根据开发人员的需要添加自己想要的注解。Java自定义注解其实是一种元注解,它可以用来标记代码或方法的各种属性。 Java的注解是在Java SE5中新增的特性,它可以用来填写源代码的元数据,在编译、加载、运行时被其他程序利用。 如…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部