Apache Commons Pool :介绍与使用

news2025/1/3 1:55:01

Apache Commons Pool :介绍与使用

什么是 commons-pool2

commons-pool2 是 Apache Commons 提供的一个开源对象池实现框架。它旨在为应用程序提供通用的对象池支持,方便开发者管理资源(如数据库连接、网络连接等)复用,从而减少资源创建与销毁的开销,提高应用程序的性能和可扩展性。


功能特性

  1. 对象池管理:
    • 提供对象的创建、复用、回收、销毁机制。
  2. 多种池实现:
    • 支持通用对象池(GenericObjectPool)和键值对象池(GenericKeyedObjectPool)。
  3. 强大的配置支持:
    • 可以自定义池大小、最大闲置数、最小闲置数等。
  4. 线程安全:
    • 内部实现了高效的并发控制。
  5. 动态调节:
    • 支持在运行时动态调整池的大小和行为。

如何使用

Maven 依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.11.1</version>
</dependency>

使用步骤

  1. 创建对象工厂:
    • 实现 org.apache.commons.pool2.PooledObjectFactory 接口,用于定义对象的创建和销毁逻辑。
  2. 初始化对象池:
    • 使用 GenericObjectPoolGenericKeyedObjectPool 来管理对象池。
  3. 获取与归还对象:
    • 使用 borrowObject() 从池中获取对象,用完后通过 returnObject() 将对象归还到池中。

示例:使用 GenericObjectPool

以下是一个简单的数据库连接池实现。

import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

// 模拟的数据库连接类
class DatabaseConnection {
    private String id;

    public DatabaseConnection(String id) {
        this.id = id;
    }

    public void connect() {
        System.out.println("Connecting to database with ID: " + id);
    }

    public void close() {
        System.out.println("Closing database connection with ID: " + id);
    }

    public String getId() {
        return id;
    }
}

// 数据库连接工厂类
class DatabaseConnectionFactory implements PooledObjectFactory<DatabaseConnection> {
    private int counter = 0;

    @Override
    public PooledObject<DatabaseConnection> makeObject() {
        DatabaseConnection connection = new DatabaseConnection("DB-" + (++counter));
        System.out.println("Creating new connection: " + connection.getId());
        return new DefaultPooledObject<>(connection);
    }

    @Override
    public void destroyObject(PooledObject<DatabaseConnection> p) {
        p.getObject().close();
    }

    @Override
    public boolean validateObject(PooledObject<DatabaseConnection> p) {
        return true; // 假设所有对象都有效
    }

    @Override
    public void activateObject(PooledObject<DatabaseConnection> p) {
        p.getObject().connect();
    }

    @Override
    public void passivateObject(PooledObject<DatabaseConnection> p) {
        // 暂时不需要实现
    }
}

public class ConnectionPoolExample {
    public static void main(String[] args) throws Exception {
        // 配置对象池
        GenericObjectPoolConfig<DatabaseConnection> config = new GenericObjectPoolConfig<>();
        config.setMaxTotal(5);          // 最大对象数
        config.setMaxIdle(3);           // 最大闲置数
        config.setMinIdle(1);           // 最小闲置数
        config.setTestOnBorrow(true);   // 借出时测试对象是否有效

        // 创建对象池
        GenericObjectPool<DatabaseConnection> pool = new GenericObjectPool<>(new DatabaseConnectionFactory(), config);

        // 使用对象池
        DatabaseConnection conn1 = pool.borrowObject(); // 从池中获取对象
        conn1.connect();

        DatabaseConnection conn2 = pool.borrowObject();
        conn2.connect();

        pool.returnObject(conn1); // 将对象归还到池中
        pool.returnObject(conn2);

        // 销毁池
        pool.close();
    }
}

输出示例

Creating new connection: DB-1
Connecting to database with ID: DB-1
Connecting to database with ID: DB-2
Closing database connection with ID: DB-1
Closing database connection with ID: DB-2

优化方式

  1. 合理配置池参数:

    • maxTotal:限制最大对象数,防止过多对象占用内存。
    • minIdle:设置最小闲置数,避免频繁创建与销毁对象。
    • maxWaitMillis:设置获取对象的超时时间。
  2. 定期测试池对象:

    • setTestOnBorrow(true):借出时验证对象。
    • setTestOnReturn(true):归还时验证对象。
    • setTestWhileIdle(true):闲置时验证对象。
  3. 监控池性能:

    • 利用池的 getNumActive()getNumIdle() 方法动态监控池中活动与闲置的对象数。
  4. 资源回收:

    • 确保池在不需要时调用 close() 释放资源。

常见场景

  1. 数据库连接池
  2. 网络连接池
  3. 线程池管理
  4. 文件句柄池

commons-pool2 闲置对象过期及设置详解

默认行为

commons-pool2 的连接池实现中,闲置对象的过期时间以及移除行为由多个参数共同决定。

默认配置

  • 默认情况下,如果没有显式设置移除闲置对象的策略,连接池中的对象可能因为资源限制而被移除。
  • 具体的移除时机依赖于如下参数设置。

相关参数详解

1. minIdle

  • 描述: 最小闲置连接数。
  • 作用: 保证连接池中始终有一定数量的对象处于闲置状态。
  • 默认值: 0(即没有保留最小闲置对象)。
  • 影响: 如果设置为较大的值,连接池会在对象被移除前尝试补充更多的空闲对象。

2. timeBetweenEvictionRunsMillis

  • 描述: 间隔多久运行一次空闲对象的逐出检查线程(以毫秒为单位)。
  • 默认值: -1(表示不运行逐出线程)。
  • 建议优化: 设置为合理的时间间隔,例如 30000 毫秒(30 秒)。

3. minEvictableIdleTimeMillis

  • 描述: 对象在池中保持空闲状态的最小时间(以毫秒为单位),超过该时间的对象可能会被移除。
  • 默认值: 1800000 毫秒(30 分钟)。
  • 建议优化: 设置为较小的值以快速移除闲置对象,例如 600000 毫秒(10 分钟)。

4. softMinEvictableIdleTimeMillis

  • 描述: 对象在池中保持空闲状态的最小时间(以毫秒为单位),但只有当空闲对象超过 minIdle 时才会被移除。
  • 默认值: 未设置。
  • 建议优化: 配合 minIdle 使用,用于延长部分闲置对象的存活时间。

5. numTestsPerEvictionRun

  • 描述: 每次空闲对象检查时检测的对象数量。
  • 默认值: -1(检查所有对象)。
  • 建议优化: 根据池的大小设置为一个合理的值,例如 10

配置示例

以下是一个完整的连接池配置示例:

import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

public class PoolConfigExample {
    public static void main(String[] args) {
        GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();

        // 设置最小空闲对象数
        config.setMinIdle(5);

        // 设置最大空闲对象数
        config.setMaxIdle(20);

        // 设置最大池容量
        config.setMaxTotal(50);

        // 设置空闲对象逐出线程运行间隔(30 秒)
        config.setTimeBetweenEvictionRunsMillis(30000);

        // 设置空闲对象的最小逐出时间(10 分钟)
        config.setMinEvictableIdleTimeMillis(600000);

        // 检查空闲对象的线程一次处理的数量
        config.setNumTestsPerEvictionRun(5);

        // 创建连接池
        GenericObjectPool<Object> pool = new GenericObjectPool<>(new MyObjectFactory(), config);

        System.out.println("连接池初始化完成!");
    }
}

// 示例对象工厂
class MyObjectFactory extends BasePooledObjectFactory<Object> {
    @Override
    public Object create() throws Exception {
        return new Object(); // 返回一个新对象
    }

    @Override
    public PooledObject<Object> wrap(Object obj) {
        return new DefaultPooledObject<>(obj);
    }
}

总结

空闲对象的移除策略

  • 默认情况下,闲置对象不会自动过期,除非设置了逐出线程参数(如 timeBetweenEvictionRunsMillis)。
  • 设置 minEvictableIdleTimeMillis 可以明确指定闲置对象的过期时间。
  • 通过调优 minIdlemaxIdle 可以更好地控制池中对象的生命周期。

推荐配置

  • 动态调整参数: 根据实际负载和资源需求动态调整 minIdletimeBetweenEvictionRunsMillis
  • 观察性能: 通过性能测试和监控,逐步优化连接池的行为,减少过期对象对系统性能的影响。

Apache Commons Pool: 最小闲置数与逐出线程的交互行为

背景介绍

Apache Commons Pool 是一个高效的对象池管理库,广泛用于连接池、线程池等需要管理资源的场景。其配置包括 最小闲置数 (minIdle)逐出线程 (Evictor) 参数。

  • 最小闲置数 (minIdle)

    • 定义对象池中需要保持的最小空闲对象数。
    • 如果空闲对象少于该值,池会创建新的对象,直到满足 minIdle
  • 逐出线程 (Evictor)

    • 周期性检查并清理空闲对象。
    • timeBetweenEvictionRunsMillisminEvictableIdleTimeMillis 参数控制。

参数交互行为

minIdle 和逐出线程参数同时设置时,逐出线程会考虑 minIdle,确保空闲对象数不低于该值。

逐出线程行为规则

  1. 逐出线程运行规则

    • 定期检查空闲对象是否超过 minEvictableIdleTimeMillis
    • 清理超过空闲时间的对象。
  2. 空闲对象保留规则

    • 如果当前空闲对象数少于或等于 minIdle,逐出线程不会清理这些对象。
    • 若空闲对象数大于 minIdle,逐出线程会清理部分对象,直到空闲对象数等于 minIdle 或更少。

参数对行为的影响

参数描述
minIdle池中最小保留空闲对象数。
timeBetweenEvictionRunsMillis逐出线程运行的时间间隔(毫秒)。
minEvictableIdleTimeMillis对象可被清理的最小空闲时间(毫秒)。

示例代码

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

public class PoolConfigExample {
    public static void main(String[] args) {
        GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();
        
        // 设置最小空闲数
        config.setMinIdle(5);
        
        // 逐出线程每30秒运行一次
        config.setTimeBetweenEvictionRunsMillis(30000);
        
        // 空闲时间超过60秒的对象可能被清理
        config.setMinEvictableIdleTimeMillis(60000);
        
        // 示例:确保至少保留5个空闲对象
        System.out.println("Pool configured with minIdle=5");
    }
}

特殊场景

  1. 最小闲置数未设置或为0

    • 空闲对象数可能会被清理为 0。
    • 下次获取对象时需要重新创建,可能导致性能下降。
  2. 逐出线程未设置

    • 空闲对象永远不会被清理,可能造成内存占用。

重要结论

  • 逐出线程不会清理到低于 minIdle 的空闲对象数
  • 如果设置合理的 minEvictableIdleTimeMillistimeBetweenEvictionRunsMillis,可以在资源回收与性能间取得平衡。
  • 配置建议:
    • 保证 minIdle 的值与系统负载需求匹配。
    • 根据对象的生命周期合理配置 minEvictableIdleTimeMillis
    • 避免过于频繁或过于稀疏的逐出线程运行时间。

总结

Apache Commons Pool 提供了灵活的参数配置,支持多种资源池管理场景。当 minIdle 和逐出线程参数同时设置时,系统会优先保证 minIdle 的空闲对象数,不会因逐出线程清理而导致空闲对象不足。合理的参数配置可以在资源利用率与性能间找到最佳平衡点。


Apache Commons Pool - 逐出线程设置指南

背景

在使用 Apache Commons Pool 进行对象池管理时,如果未设置逐出线程,空闲对象将永远不会被清理,可能导致内存占用问题。因此,合理配置逐出线程的相关参数可以避免资源泄露,提高系统性能。


关键参数

timeBetweenEvictionRunsMillis

  • 作用:控制逐出线程的运行周期(以毫秒为单位)。
  • 默认值-1,表示逐出线程不运行。
  • 建议设置:例如 60000 表示每分钟运行一次。

minEvictableIdleTimeMillis

  • 作用:设置空闲对象被逐出的最小生存时间(以毫秒为单位)。
  • 默认值1800000(30 分钟)。
  • 建议设置:根据业务需求调整,例如 10 分钟:600000

minIdle

  • 作用:确保池中始终保持的最小空闲对象数。即使逐出线程运行,也不会清理低于该数量的空闲对象。
  • 建议设置:根据系统负载调整,例如 5

maxIdle

  • 作用:限制池中空闲对象的最大数量。如果空闲对象超过此值,多余的对象会被逐出。
  • 建议设置:例如 10

配置代码示例

以下代码展示如何通过 GenericObjectPool 设置逐出线程:

import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

public class PoolExample {
    public static void main(String[] args) {
        // 配置池参数
        GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();

        // 设置最小空闲连接数
        config.setMinIdle(5);

        // 设置最大空闲连接数
        config.setMaxIdle(10);

        // 设置最大连接数
        config.setMaxTotal(20);

        // 逐出线程运行周期(每 60 秒运行一次)
        config.setTimeBetweenEvictionRunsMillis(60000);

        // 最小可逐出时间(30 分钟未使用的空闲对象会被清理)
        config.setMinEvictableIdleTimeMillis(1800000);

        // 创建对象池
        GenericObjectPool<Object> pool = new GenericObjectPool<>(new ObjectFactory(), config);

        // 使用对象池
        try {
            Object obj = pool.borrowObject(); // 获取对象
            pool.returnObject(obj);           // 归还对象
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            pool.close(); // 关闭池
        }
    }

    // 自定义对象工厂
    static class ObjectFactory extends BasePooledObjectFactory<Object> {
        @Override
        public Object create() {
            return new Object(); // 创建对象
        }

        @Override
        public PooledObject<Object> wrap(Object obj) {
            return new DefaultPooledObject<>(obj); // 包装对象
        }
    }
}

参数详细说明

参数名称作用示例值
setTimeBetweenEvictionRunsMillis控制逐出线程的运行周期。正值表示启用逐出线程,例如 60000 表示每分钟运行一次。60000
setMinEvictableIdleTimeMillis空闲对象的最小生存时间,超过此时间的对象会被逐出。1800000
setMinIdle保证的最小空闲对象数,即使逐出线程运行,也不会清理低于该数量的对象。5
setMaxIdle最大空闲对象数,超过此值的对象会被逐出。10

配置文件示例

可以通过 properties 文件加载配置:

pool.minIdle=5
pool.maxIdle=10
pool.maxTotal=20
pool.timeBetweenEvictionRunsMillis=60000
pool.minEvictableIdleTimeMillis=1800000

在代码中加载配置:

Properties props = new Properties();
try (InputStream input = new FileInputStream("config.properties")) {
    props.load(input);
    GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();
    config.setMinIdle(Integer.parseInt(props.getProperty("pool.minIdle")));
    config.setMaxIdle(Integer.parseInt(props.getProperty("pool.maxIdle")));
    config.setMaxTotal(Integer.parseInt(props.getProperty("pool.maxTotal")));
    config.setTimeBetweenEvictionRunsMillis(Long.parseLong(props.getProperty("pool.timeBetweenEvictionRunsMillis")));
    config.setMinEvictableIdleTimeMillis(Long.parseLong(props.getProperty("pool.minEvictableIdleTimeMillis")));
}

优化建议

  1. 合理设置最小和最大空闲对象数:避免频繁创建和销毁对象。
  2. 监控池性能:通过池提供的指标(例如活动对象数、空闲对象数)动态调整配置。
  3. 避免逐出线程频繁运行:将逐出线程运行周期设置为合理的值,例如 1 分钟或更长时间。
  4. 测试与调优:根据实际使用场景不断调整参数,平衡性能与资源消耗。

通过合理设置逐出线程和相关参数,可以显著提高对象池的性能和资源利用效率。


线程数量逐渐增加的原因分析与参数设置建议

当线程数量逐渐增加时,可能是由于以下原因或参数设置的问题导致的。以下是详细分析及解决方法。


1. 未限制线程池最大线程数量

  • 原因

    • 未设置线程池的最大线程数 (maxTotal),默认值可能非常大甚至是无界的。随着任务增加,线程池不断创建新线程来满足请求,导致线程数量逐渐增加。
  • 解决方法

    • 设置合理的 maxTotal 值,以限制线程池中的最大线程数。

2. 核心线程数设置过高

  • 原因

    • corePoolSize 是线程池中核心线程的数量。如果设置过高,即使任务较少,线程池也会保持较多的核心线程。
  • 解决方法

    • 根据实际需求,设置一个合理的 corePoolSize 值,以减少空闲线程的数量。

3. 空闲线程未被回收

  • 原因

    • 空闲线程的生存时间参数 (minEvictableIdleTimeMillis) 过长,导致空闲线程无法及时被逐出。
  • 解决方法

    • 设置 minEvictableIdleTimeMillis 为合理的时间(如 30 秒或 60 秒),使得空闲线程能在闲置一段时间后被回收。

4. 逐出线程未启动

  • 原因

    • 未启用逐出线程(Evictor),导致空闲线程不会被定期清理,线程池中的线程数量可能持续累积。
  • 解决方法

    • 设置 timeBetweenEvictionRunsMillis 为一个正值(如 30000 毫秒),开启逐出线程。
    • 配合使用 minEvictableIdleTimeMillisnumTestsPerEvictionRun 参数进行逐出策略优化。

5. 任务积压导致线程池扩容

  • 原因

    • 线程池的队列(workQueue)容量不足时,新任务可能会触发线程池动态扩容。如果任务积压过多,线程池可能创建更多线程来处理任务。
  • 解决方法

    • 使用有限大小的阻塞队列(如 LinkedBlockingQueue),并合理设置其容量。
    • 设置 maximumPoolSize 限制线程数量的扩展。

6. 线程工厂问题

  • 原因

    • 如果线程池使用的 ThreadFactory 未正确管理线程,可能会导致线程池创建更多的线程。
  • 解决方法

    • 确保 ThreadFactory 正确实现,并为线程池创建的线程设置合理的优先级、命名和守护线程属性。

7. 线程泄漏

  • 原因

    • 某些任务未正常退出线程,或线程被错误地持久化,导致线程池中的线程无法被回收。
  • 解决方法

    • 定期监控线程池中的活动线程数。
    • 确保任务逻辑正确,避免线程长期处于阻塞状态。

参数设置示例

以下是一个合理的线程池参数设置,避免线程数量逐渐增加:

GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(100); // 设置线程池最大线程数
config.setMinIdle(10);  // 设置最小闲置线程数
config.setMaxIdle(50);  // 设置最大闲置线程数
config.setTimeBetweenEvictionRunsMillis(30000); // 逐出线程运行间隔
config.setMinEvictableIdleTimeMillis(60000);   // 最小闲置时间
config.setNumTestsPerEvictionRun(3);           // 每次逐出线程检测的对象数

通过合理的参数设置,可以有效控制线程数量,避免不必要的资源消耗。


对象清理行为分析及配置

问题描述

最小闲置数未设置或为0逐出线程未设置 的情况下,如何清理空闲对象?是优先清理最小闲置数为0的对象,还是优先考虑逐出线程未设置的情况,即使最小闲置数为0也不清理?


行为规则分析

1. 最小闲置数未设置或为0

  • 效果
    • 如果 minIdle 设置为 0 或未设置,则空闲池对象可以降到 0 个,即没有任何最小保留的连接或线程。
    • 但仅此设置并不会直接导致清理,因为清理动作需要逐出线程的参与。

2. 逐出线程未设置

  • 效果
    • 如果没有设置逐出线程(即未配置 evictor),则系统不会主动清理空闲对象。
    • 即使 minIdle0,由于缺少逐出线程触发,空闲对象仍然会长期存在。

3. 优先顺序

  • 逐出线程优先控制清理逻辑:如果没有逐出线程,即使 minIdle0,也不会清理空闲对象。
  • 清理动作需要逐出线程定期检查并触发。

总结行为

1. 逐出线程未设置的情况

  • 空闲对象永远不会被清理。
  • 即使 minIdle0,对象也会一直存在,导致资源可能被长期占用。

2. 逐出线程设置了,但 minIdle 为0的情况

  • 逐出线程会按照配置定期运行,清理空闲对象,直到池中对象数量为 0

优化建议

1. 如果希望空闲对象及时释放:

  • 配置逐出线程参数:
    • timeBetweenEvictionRunsMillis:逐出线程运行的时间间隔(单位:毫秒)。
    • minEvictableIdleTimeMillis:空闲对象被逐出的最短存活时间(单位:毫秒)。
  • 设置 minIdle 为合适的非零值(如 minIdle = 2),确保资源池中保留一定数量的空闲对象。

2. 如果不希望清理空闲对象:

  • 设置 minIdle 为大于 0 的值(如 minIdle = 5)。
  • 不设置逐出线程参数,或将 timeBetweenEvictionRunsMillis 设置为一个较大的值,避免频繁触发清理。

示例代码

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

GenericObjectPoolConfig<?> config = new GenericObjectPoolConfig<>();

// 设置最小闲置数为 0
config.setMinIdle(0);

// 配置逐出线程,每 30 秒运行一次
config.setTimeBetweenEvictionRunsMillis(30000);

// 空闲对象超过 60 秒被逐出
config.setMinEvictableIdleTimeMillis(60000);

参数含义

参数名说明示例值
minIdle最小闲置对象数0
timeBetweenEvictionRunsMillis逐出线程运行间隔30000
minEvictableIdleTimeMillis空闲对象存活时间60000

通过合理的配置,可以有效管理资源池对象的生命周期,防止资源浪费或内存泄漏,同时提升系统性能。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2268314.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mumu模拟器12开启ADB调试方法

在使用安卓模拟器进行开发或调试时&#xff0c;ADB&#xff08;Android Debug Bridge&#xff09;是一项不可或缺的工具。大多数模拟器默认开启了ADB调试功能&#xff0c;但在安装最新版的 Mumu模拟器12 时&#xff0c;可能会遇到 adb devices 无法识别设备的问题。 问题描述 …

金融租赁系统的创新发展与市场竞争力提升探讨

内容概要 随着经济的快速发展&#xff0c;金融租赁系统逐渐成为金融市场中不可或缺的一环。它不仅提供了灵活的资金解决方案&#xff0c;还促进了企业的资本结构优化与资源配置效率。因此&#xff0c;了解该系统的市场背景与发展现状至关重要。 在现今环境下&#xff0c;新兴…

SQL 实战:基于经纬度的距离计算与位置查询

在位置服务&#xff08;LBS&#xff09;系统中&#xff0c;基于地理位置查询和距离计算是核心功能之一。例如&#xff1a; 查找附近的商铺、加油站或医院。计算两点之间的实际直线距离。筛选出指定范围内的用户或设备位置。 MySQL 提供了多种方式实现地理位置查询&#xff0c…

DAY1牛客题库1-3算法题:C语言版本(思路仅供参考)

挑战一下7天刷完牛客题库的108个题&#xff0c;今天是第一天思密达~一直以来都特别懒的做题&#xff0c;还是得勤奋点我觉得~今天只做了3个~嘻嘻明天去玩回家多弄几个~ 1.输出字符串最后一个单词长度 【1】题目&#xff1a; #include"stdio.h" #include"string…

LeetCode 83 :删除排链表中的重复元素

题目&#xff1a; 地址&#xff1a;https://leetcode.cn/problems/remove-duplicates-from-sorted-list/ 方法一&#xff1a; 方法二&#xff1a; package com.zy.leetcode.LeetCode_04;/*** Author: zy* Date: 2024-12-25-15:19* Description: 删除排链表中的里复元素* …

微信流量主挑战:用户破16!新增文档转换(新纪元3)

朋友们&#xff0c;报告好消息&#xff01;我的小程序用户数量已经涨到16个了&#xff01;没错&#xff0c;真没拉朋友圈亲戚好友来撑场子&#xff0c;全靠实力&#xff08;和一点点运气&#xff09;吸引了16位陌生小伙伴光临&#xff01;这波进步&#xff0c;连我自己都感动了…

Java-38 深入浅出 Spring - AOP切面增强 核心概念 相关术语 Proxy配置

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大数据篇正在更新&#xff01;https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了&#xff1a; MyBatis&#xff…

基于Docker+模拟器的Appium自动化测试(二)

模拟器的设置 打开“夜神模拟器”的系统设置&#xff0c;切换到“手机与网络”页&#xff0c;选中网络设置下的“开启网络连接”和“开启网络桥接模式”复选框&#xff0c;而后选择“静态IP”单选框&#xff0c;在IP地址中输入“192.168.0.105”&#xff0c;网关等内容不再赘述…

【从零开始入门unity游戏开发之——C#篇36】C#的out协变和in逆变如何解决泛型委托的类型转换问题

文章目录 一、知识回顾和问题分析1、回顾强制转换和as转换知识2、问题分析 二、为什么泛型委托不行&#xff1f;1、泛型类型的严格类型检查2、**as 和强制类型转换不能直接使用** 三、如何解决这个问题&#xff1f;1、**协变&#xff08;out&#xff09;**2、**逆变&#xff08…

深度学习使用Anaconda打开Jupyter Notebook编码

新手入门深度学习使用Anaconda打开Jupyter Notebook编码 1. 安装Anaconda 第一种是Anaconda官网下载安装包&#xff0c;但是很慢&#xff0c;不太建议 第二种使用国内清华大学镜像源下载 选择适合自己电脑的版本&#xff0c;支持windows&#xff0c;linux系统 下载完之后自行…

Linux套接字通信学习

Linux套接字通信 代码源码&#xff1a;https://github.com/say-Hai/TcpSocketLearn/tree/CThreadSocket 在网络通信的时候, 程序猿需要负责的应用层数据的处理(最上层)&#xff0c;而底层的数据封装与解封装&#xff08;如TCP/IP协议栈的功能&#xff09;通常由操作系统、网络协…

git clone 和 conda 换源

文章目录 git clone 通过 sshconda 创建虚拟环境通过 env.yml 文件conda 换源 git clone 通过 ssh git clone ssh://用户名IP地址:/仓库名字.gitconda 创建虚拟环境通过 env.yml 文件 conda env create -f environment.ymlconda 换源 Step 1 生成 .bashrc 文件在家目录下。…

机床数据采集网关在某机械制造企业的应用

随着工业4.0时代的到来&#xff0c;智能制造已成为制造业转型升级的重要方向。数控机床作为现代制造业的核心设备&#xff0c;其运行状态和加工参数的数据实时采集与分析对于提升生产效率、优化生产流程具有关键意义。 背景概述 某机械制造企业拥有多台数控机床&#xff0c;这…

c# RSA加解密工具,.netRSA加解密工具

软件介绍 名称: c# RSA加解密工具,.netRSA加解密工具依赖.net版本: .net 8.0工具类型: WinForm源码下载 c# RSA加解密工具,.netRSA加解密工具 依赖项 WinFormsRSA.csproj <Project

穷举vs暴搜vs深搜vs回溯vs剪枝_全排列_子集

46. 全排列 递归解决&#xff1a;一开始选一个数&#xff0c;递归进入下一层再选一个新的数&#xff0c;直到到最后一个数。反会上一层遍历其它数。 每次递归到叶子节点就找到了一种组合&#xff0c;思路有了具体怎么实现&#xff1f; 1.怎么记录每条路径&#xff1f; 定义一个…

【Trick】获取kaggle账号的token和api(用于数据集下载)

0&#xff1a;操作背景 由于未来的科研需要用到Unet&#xff0c;但是运行学长的史山代码无法跑通&#xff0c;自己写了一个Unet并load学长的数据集效果也很差&#xff0c;于是打算从最最基础的开始&#xff0c;上github调用一个Unet并成功在公有数据集上跑一遍实例。 Unet的g…

VS Code AI开发之Copilot配置和使用详解

随着AI开发工具的迅速发展&#xff0c;GitHub Copilot在Cursor、Winsuf、V0等一众工具的冲击下&#xff0c;推出了免费版本。接下来&#xff0c;我将为大家介绍GitHub Copilot的配置和使用方法。GitHub Copilot基于OpenAI Codex模型&#xff0c;旨在为软件开发者提供智能化的代…

论文解读 | NeurIPS'24 Lambda:学习匹配先验以处理无标记垂悬问题场景下的实体对齐任务...

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击 阅读原文 观看作者讲解回放&#xff01; 作者简介 尹航&#xff0c;上海交通大学博士生 内容简介 我们研究了带有无标记悬挂问题的实体对齐&#xff08;EA&#xff09;任务&#xff0c;即部分实体在另一个…

评分模型在路网通勤习惯分析中的应用——提出问题(1)

1、问题的由来、目标和意义 最近一段时间和公司其它业务部门讨论时&#xff0c;发现一个有趣的交通路网问题&#xff0c;车辆从S点行驶到V点共用时40分钟&#xff0c;这段时间内路网中的卡口摄像头识别到了车辆通过的信息。如下图所示&#xff1a; 设计师需要通过这些有限的路…

Spring Security day 11.23

ok了今天学习一个关于登录角色权限的管理框架&#xff0c;我们一起取看看吧 一.权限控制 1.1 认证和授权概念 前面我们已经完成了后台管理系统的部分功能&#xff0c;例如检查项管 理、检查组管理、套餐管理、预约设置等。接下来我们需要思 考 2 个问题&#xff1a; 问题 1 …