面试题答案
一键面试对象池设计理念
对象池旨在复用已创建的对象,避免频繁创建和销毁对象带来的性能开销。通过预先创建一定数量的对象并存储在池中,当有对象需求时,从池中获取,使用完毕后再放回池中,从而提高系统性能和资源利用率。
对象池实现方式
- 对象创建:在初始化阶段,根据需求创建一定数量的对象实例并放入池中。
- 对象获取:当外部请求对象时,从池中查找可用对象返回。若池中无可用对象,根据策略(如等待或新建)处理。
- 对象归还:使用完对象后,将其归还给对象池,标记为可用状态。
对象池适用场景
- 创建开销大的对象:如数据库连接、线程、Socket连接等,频繁创建和销毁会严重影响性能。
- 对象使用频率高:经常需要使用相同类型的对象,复用可节省时间和资源。
数据库连接对象池设计关键因素
- 资源管理:控制连接数量,避免过多连接耗尽系统资源。包括初始化连接数、最大连接数、最小连接数等参数设置。
- 并发控制:确保多个线程安全地获取和归还连接。使用锁机制或并发集合来管理连接的访问。
- 连接有效性检查:定期检查连接是否有效,若无效则从池中移除并重新创建。
- 连接超时处理:设置获取连接的超时时间,避免线程无限期等待。
核心设计思路
- 定义连接池类,包含连接集合、连接参数等成员变量。
- 实现初始化方法,创建初始连接并放入池中。
- 实现获取连接方法,使用锁机制确保线程安全获取连接,同时处理连接超时。
- 实现归还连接方法,将使用后的连接放回池中,并标记为可用。
关键代码片段
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DatabaseConnectionPool {
private static final String URL = "jdbc:mysql://localhost:3306/yourdatabase";
private static final String USER = "yourusername";
private static final String PASSWORD = "yourpassword";
private static final int INITIAL_POOL_SIZE = 5;
private static final int MAX_POOL_SIZE = 10;
private static final int CONNECTION_TIMEOUT = 5000; // 5 seconds
private List<Connection> connectionPool;
private List<Connection> usedConnections;
private Lock lock;
private Condition condition;
public DatabaseConnectionPool() {
connectionPool = new ArrayList<>();
usedConnections = new ArrayList<>();
lock = new ReentrantLock();
condition = lock.newCondition();
initializePool();
}
private void initializePool() {
for (int i = 0; i < INITIAL_POOL_SIZE; i++) {
Connection connection = createConnection();
if (connection != null) {
connectionPool.add(connection);
}
}
}
private Connection createConnection() {
try {
return DriverManager.getConnection(URL, USER, PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
public Connection getConnection() throws InterruptedException {
lock.lock();
try {
long endTime = System.currentTimeMillis() + CONNECTION_TIMEOUT;
while (connectionPool.isEmpty() && System.currentTimeMillis() < endTime) {
condition.await(endTime - System.currentTimeMillis());
}
if (connectionPool.isEmpty()) {
throw new InterruptedException("Timeout waiting for connection");
}
Connection connection = connectionPool.remove(0);
usedConnections.add(connection);
return connection;
} finally {
lock.unlock();
}
}
public void returnConnection(Connection connection) {
lock.lock();
try {
if (usedConnections.remove(connection)) {
connectionPool.add(connection);
condition.signal();
}
} finally {
lock.unlock();
}
}
public void closeAllConnections() {
lock.lock();
try {
for (Connection connection : connectionPool) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
for (Connection connection : usedConnections) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
connectionPool.clear();
usedConnections.clear();
} finally {
lock.unlock();
}
}
}
使用示例:
public class Main {
public static void main(String[] args) {
DatabaseConnectionPool pool = new DatabaseConnectionPool();
try {
Connection connection = pool.getConnection();
// 使用连接执行数据库操作
pool.returnConnection(connection);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
pool.closeAllConnections();
}
}
}