Java线程池复用线程的秘密你知道吗

Java线程池复用线程的秘密你知道吗

线程池的工作原理

线程池是专门用来管理线程的,其主要作用是维护一个空闲的线程队列和一个任务队列,将任务提交到线程池后,线程池会从线程队列中取出一个空闲线程,然后将任务分配给该线程执行,任务执行完毕后该线程就会返回线程队列等待执行下一个任务,这样就能大大提升线程的复用率和运行效率。

线程复用的实现

线程池中的线程是可以复用的,这是因为线程池在创建线程时使用了线程池缓存技术,即如果当前线程池中存在空闲线程,则将该空闲线程从线程池中取出并分配新的任务执行;如果线程池中不存在空闲线程,则会根据线程池的配置创建新的线程。

线程复用的具体实现方式有两种:

  1. 通过线程池缓存技术实现

java
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE, // 线程池核心线程数
MAX_POOL_SIZE, // 线程池最大线程数
KEEP_ALIVE_TIME, // 线程池空闲线程存活时间
TimeUnit.SECONDS, // 线程池空闲线程存活时间单位
new ArrayBlockingQueue<>(QUEUE_SIZE) // 线程池任务队列
);

线程池会在初始化时创建CORE_POOL_SIZE个线程,如果当任务量过大时,线程池会在达到MAX_POOL_SIZE前扩容,增加新的线程继续执行任务。在线程数达到CORE_POOL_SIZE之后,如果有空闲线程,则该任务会优先分配给空闲线程执行,否则该任务会进入到任务队列中等待执行。

  1. 通过线程复用技术实现

线程复用技术是指将线程池中的线程封装成一个可回收的线程对象,任务执行完以后不会被销毁,而是将该线程返回到线程池中继续待命,等待下一轮任务分配。

```java
public class ReusableThread implements Runnable {

   private ThreadPoolExecutor executor;

   public void setThreadPoolExecutor(ThreadPoolExecutor executor) {
       this.executor = executor;
   }

   @Override
   public void run() {
       while (true) {
           try {
               runnable.run();
           } catch (Throwable t) {
               // handle exception
           } finally {
               if (executor != null) {
                   executor.reuse(this); // 将线程对象返回到线程池中,继续待命
               }
           }
       }
   }

}
```

线程执行完任务后,会调用ThreadPoolExecutor的reuse方法,将线程返回到线程池中,线程池会继续使用该线程执行下一个任务。这样就实现了对线程的复用。

示例说明

示例1

假设有一个服务器需要处理客户端的请求,每个请求都需要新建一个线程来处理。为了避免线程过多导致系统负载过高,可以使用线程池来管理线程,降低系统负载。

public class Server {
    ThreadPoolExecutor executor = new ThreadPoolExecutor(
        5, // 线程池核心线程数
        10, // 线程池最大线程数
        10, // 线程池空闲线程存活时间
        TimeUnit.SECONDS, // 线程池空闲线程存活时间单位
        new LinkedBlockingQueue<>() // 线程池任务队列,使用无界队列
    );

    public void handleRequest(Request request) {
        // 将请求提交到线程池执行
        executor.execute(new Handler(request));
    }

    private class Handler implements Runnable {
        private Request request;

        public Handler(Request request) {
            this.request = request;
        }

        @Override
        public void run() {
            // 处理请求
            // ...
        }
    }
}

在上面的代码中,当有新的请求到达时,会将该请求封装成一个Handler对象,并将该Handler对象提交到线程池中执行。线程池在执行Handler对象时,会从空闲线程队列中选取一个线程执行,如果当前没有空闲线程,则线程池会创建新的线程来执行。执行完Handler对象后,线程会返回线程池,等待下一次任务分配。

示例2

假设有一个需要进行大量计算的任务,可以使用线程池来提高计算效率。下面是一个计算圆周率的示例。

public class PiCalculator {
    ThreadPoolExecutor executor = new ThreadPoolExecutor(
        5, // 线程池核心线程数
        10, // 线程池最大线程数
        10, // 线程池空闲线程存活时间
        TimeUnit.SECONDS, // 线程池空闲线程存活时间单位
        new LinkedBlockingQueue<>() // 线程池任务队列,使用无界队列
    );
    private int numThreads;
    private int iterations;
    private AtomicInteger hitCounter = new AtomicInteger(0);

    public PiCalculator(int numThreads, int iterations) {
        this.numThreads = numThreads;
        this.iterations = iterations;
    }

    public double calculate() {
        for (int i = 0; i < numThreads; i++) {
            executor.submit(new Calculator());
        }

        executor.shutdown();

        try {
            executor.awaitTermination(10, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            // handle interrupt exception
        }

        return 4.0 * hitCounter.get() / (iterations * numThreads);
    }

    private class Calculator implements Runnable {
        private Random rand = new Random();

        @Override
        public void run() {
            int hits = 0;
            for (int i = 0; i < iterations; i++) {
                double x = rand.nextDouble();
                double y = rand.nextDouble();
                if (x * x + y * y <= 1) {
                    hits++;
                }
            }
            hitCounter.addAndGet(hits);
        }
    }
}

在上面的代码中,可以看到使用了线程池来并行计算圆周率。将计算任务分解成多个线程,每个线程计算部分结果,最终汇总得到最终结果。在线程执行完计算任务后,会将线程返回到线程池中,继续待命,等待下一轮计算任务的分配。这样能大大提高计算效率和系统吞吐量。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java线程池复用线程的秘密你知道吗 - Python技术站

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

相关文章

  • java 学习笔记(入门篇)_程序流程控制结构和方法

    Java 学习笔记(入门篇)- 程序流程控制结构和方法 在 Java 程序开发中,掌握程序流程控制结构和方法是非常重要的,因为它们可以帮助我们控制程序的执行流程,并且提高程序的可读性和可维护性。本文将详细讲解 Java 中的程序流程控制结构和方法,希望能够帮助初学者快速掌握。 1. 程序流程控制结构 1.1 分支结构 在 Java 中,我们可以使用 if、s…

    Java 2023年5月23日
    00
  • AndroidStudio插件GsonFormat之Json快速转换JavaBean教程

    下面是“AndroidStudio插件GsonFormat之Json快速转换JavaBean教程”的详细攻略: 什么是GsonFormat插件? GsonFormat是一款Android Studio插件,使用该插件能够通过json数据自动生成JavaBean模板,从而加快开发者的开发速度,避免一些手工编写代码造成的错误。 GsonFormat插件的安装 打…

    Java 2023年5月26日
    00
  • jsp输出九九乘法表的简单实例

    我将为您详细讲解“JSP输出九九乘法表的简单实例”的攻略: 前置条件: 需要安装本地的 Java 和 Tomcat 环境,同时需要了解基本的 JSP 开发知识。 创建 JSP 页面 首先,我们需要在 Tomcat 中创建一个 JSP 页面,用于输出九九乘法表。可以在本地的 Tomcat 服务器中的 webapps 目录下创建一个新的文件夹(例如叫做“jmf”…

    Java 2023年6月15日
    00
  • Java实战之实现一个好用的MybatisPlus代码生成器

    首先需要明确的是,MybatisPlus是Mybatis的一个增强版本,能够大大提高开发效率。而MybatisPlus代码生成器能够自动生成基本的CRUD操作,这对于快速搭建项目是非常有帮助的。下面我将详细讲解如何实现一个好用的MybatisPlus代码生成器。 准备工作 添加MybatisPlus及其依赖到项目中。 创建数据库及数据表。(以下示例中,我们使…

    Java 2023年5月19日
    00
  • 详解Spring Security 简单配置

    《详解Spring Security 简单配置》是一篇介绍如何简单配置Spring Security的文章。下面是详细攻略: 1. 引入依赖 首先需要在项目中引入Spring Security的依赖,可以从Maven Central Repository中搜索Spring Security依赖,选择适合的版本引入。 2. 配置Spring Security …

    Java 2023年5月20日
    00
  • 使用Java实现类似Comet风格的web app

    针对使用Java实现类似Comet风格的web app,我可以给您提供以下的攻略: 一、了解Comet Comet是一种Web服务器向浏览器发送异步数据的技术。在传统的Web应用程序中,客户端通过HTTP协议发起请求,服务器收到请求后即时返回响应。而Comet则是一种在Web服务器与浏览器之间建立持久连接的技术,使得服务端可以在有数据更新时主动向客户端推送数…

    Java 2023年5月19日
    00
  • spring-spring容器中bean知识点总结

    Spring 容器中 Bean 知识点总结 Spring 是一个开源的框架,它解决了企业级应用中复杂性规模的问题。其中最常用的就是 Spring 容器中的 Bean,本文将详细讲解 Spring 容器中 Bean 的知识点总结。 什么是 Spring 容器? Spring 容器是一个管理 Bean 的运行环境,它负责创建 Bean 对象、配置 Bean 属性…

    Java 2023年6月15日
    00
  • SpringBoot SpringEL表达式的使用

    SpringEL表达式的使用攻略 1. SpringEL表达式的概述 Spring Expression Language(简称Spring EL)是一种表达式语言,用于在Spring应用程序中访问和操作对象图。它支持在运行时查询和操作对象图。 在Spring Boot应用程序中,可以使用Spring EL表达式来配置应用程序的各种组件,如依赖注入、AOP等…

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