线程池和连接池

线程池(ThreadPool)

线程池详解
1. 线程池的作用

线程池是一种线程使用模式,它主要解决两个问题:

  1. 重复利用线程:避免频繁创建和销毁线程,减少系统开销。
  2. 控制线程数量:限制线程的最大并发数,避免系统资源过度消耗。

其他优势包括:

  • 提高响应速度:重用线程避免了线程创建的延迟。
  • 提高线程的可管理性:统一管理,方便监控。
2. 线程池的创建
2.1 使用Executors工厂方法

Java提供了Executors类,其中包含多个静态工厂方法来创建不同类型的线程池:

ExecutorService executorService = Executors.newFixedThreadPool(2); // 这里的线程池里面的线程数量为2

常用的工厂方法包括:

  • newFixedThreadPool(int nThreads): 创建固定大小的线程池
  • newCachedThreadPool(): 创建可缓存的线程池
  • newSingleThreadExecutor(): 创建单线程的线程池
  • newScheduledThreadPool(int corePoolSize): 创建可以执行定时任务的线程池
2.2 手动创建ThreadPoolExecutor(拓展)

对于更精细的控制,可以直接使用ThreadPoolExecutor类:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS,
    new LinkedBlockingQueue<Runnable>()
);
3. 线程池的使用
3.1 提交任务

可以通过execute()方法提交Runnable任务:

executorService.execute(new Runnable() {
    @Override
    public void run() {
        // 任务代码
    }
});

或者使用submit()方法提交Callable任务(可以有返回值)。

3.2 关闭线程池
  • shutdown(): 温和地关闭线程池,等待所有任务完成。
  • shutdownNow(): 立即关闭线程池,尝试中断正在执行的任务。
executorService.shutdown();
// 或
// executorService.shutdownNow();
4. 依赖

线程池相关的类都在java.util.concurrent包中,是Java标准库的一部分,不需要额外的依赖。

主要用到的类:

  • java.util.concurrent.ExecutorService
  • java.util.concurrent.Executors
  • java.util.concurrent.ThreadPoolExecutor
5. 线程池的参数

使用ThreadPoolExecutor时,可以设置以下参数:

  • corePoolSize: 核心线程数
  • maximumPoolSize: 最大线程数
  • keepAliveTime: 线程空闲时间
  • workQueue: 工作队列,用于存放任务
  • threadFactory: 线程工厂,用于创建线程
  • handler: 拒绝策略,当任务太多时如何处理
6. 注意事项
  • 避免使用Executors创建线程池,因为它可能导致OOM(内存溢出)。推荐直接使用ThreadPoolExecutor
  • 合理设置线程池大小,考虑CPU核心数、内存大小等因素。
  • 注意监控线程池的状态,及时调整参数。
  • 记得在应用程序结束前关闭线程池。
7. 示例代码解析
ExecutorService executorService = Executors.newFixedThreadPool(2);

创建了一个固定大小为2的线程池。

for (int i = 0; i < 5; i++){
    // 创建并提交任务
}

循环创建5个任务并提交给线程池。

executorService.shutdown();

关闭线程池,等待所有任务完成。

这个示例展示了如何创建线程池、提交任务和关闭线程池的基本操作。

8. 具体实例

image-20240703200058869

连接池

数据库连接池详解
1. 连接池的作用

数据库连接池主要解决以下问题:

  1. 提高性能:避免频繁地创建和关闭数据库连接,减少系统开销。
  2. 资源管理:限制数据库连接的数量,防止数据库服务器过载。
  3. 提高可用性:预先创建连接,减少获取连接的等待时间。
  4. 连接重用:允许多个请求共享同一个连接,提高资源利用率。
2. 连接池的实现(基于提供的代码)
2.1 使用 Druid 连接池
private static DruidDataSource ds;

static {
    ds = new DruidDataSource();
    ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
    ds.setUrl("jdbc:mysql://localhost:3306/jdbc_study?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true");
    ds.setUsername("root");
    ds.setPassword("root");
    ds.setMaxActive(20);  // 最大连接数
    ds.setInitialSize(5); // 初始化连接数
}

这段代码初始化了 Druid 连接池,设置了数据库驱动、URL、用户名、密码等基本信息,以及最大连接数和初始连接数。

2.2 获取连接
public static Connection getConnection() throws Exception {
    return ds.getConnection();
}

这个方法从连接池中获取一个连接。当调用此方法时,如果池中有可用连接,就直接返回;如果没有,可能会创建新的连接(取决于池的配置)。

3. 连接池的优势
  1. 性能提升:重用连接减少了创建和销毁连接的开销。
  2. 资源控制:可以限制最大连接数,防止数据库过载。
  3. 响应速度:预创建连接减少了等待时间。
  4. 统一管理:集中管理数据库连接,便于监控和调优。
4. 应用场景
  1. 高并发web应用:大量用户同时访问数据库时。
  2. 数据密集型应用:需要频繁数据库操作的场景。
  3. 分布式系统:多个服务需要共享数据库资源时。
  4. 微服务架构:每个微服务可能需要独立的数据库连接池。
5. 连接池的关键参数
  • MaxActive:最大活跃连接数
  • InitialSize:初始连接数
  • MinIdle:最小空闲连接数
  • MaxWait:获取连接最大等待时间
6. 最佳实践
  1. 合理设置池大小:根据系统并发量和数据库性能调整。
  2. 监控连接池状态:关注连接使用情况,及时调整参数。
  3. 使用预编译语句:可以配合连接池使用,进一步提高性能。
  4. 及时释放连接:使用完毕后及时将连接返回池中。
7. 注意事项
  1. 避免连接泄露:确保在 finally 块中关闭连接。
  2. 定期检查空闲连接:移除长时间不用的连接。
  3. 考虑使用连接池框架:如 Druid、HikariCP 等,它们提供了更多高级特性。
8. 代码中的改进点
  1. 可以考虑将数据库配置信息外部化,例如放在配置文件中。
  2. 添加更多的连接池配置,如最小空闲连接数、连接最大存活时间等。
  3. 实现一个关闭连接池的方法,在应用程序结束时调用。

通过使用连接池,您的应用程序可以更高效地管理数据库连接,提高性能和可扩展性。在实际应用中,需要根据具体场景调整连接池的参数,以达到最佳效果。

9. 代码参考示例
package socket;

import com.alibaba.druid.pool.DruidDataSource;

import java.sql.Connection;
import java.sql.DriverManager;

public class DBUtil {
    // 静态连接池
    private static DruidDataSource ds;

    //数据库工具类
    static{
        /*
        try{
            // 反射机制获取类对象
            Class.forName("com.mysql.cj.jdbc.Driver");
            //
        }catch (Exception e){
            e.printStackTrace();
        }*/
        // 实例化连接池
        ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        String databaseName = "jdbc_study";
        ds.setUrl("jdbc:mysql://localhost:3306/"+databaseName+"?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true");
        ds.setUsername("root");
        ds.setPassword("root");
        ds.setMaxActive(20);  // 最大连接数

        ds.setInitialSize(5); // 初始化连接数
    }

    // 静态方法获取连接
    // 之所以使用throw Exception,是为了让调用者处理异常,而不是创建者处理异常
    public static Connection getConnection() throws Exception{
        // 在静态块中加载驱动

        /*// 返回获取的连接
        String databaseName = "jdbc_study";
        return DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/"+databaseName+"?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true",
                "root",
                "root"
        );*/
        // 返回连接池中的连接
        return ds.getConnection();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值