面试题答案
一键面试Java固定数目线程池中线程复用原理
在Java的固定数目线程池(如ThreadPoolExecutor
通过Executors.newFixedThreadPool(int nThreads)
创建的线程池)中,线程复用基于以下机制:
- 任务队列:当提交新任务时,如果线程池中有空闲线程,任务会被分配给空闲线程执行。若所有线程都在忙碌,任务会被放入任务队列(
BlockingQueue
)中等待。 - 线程生命周期管理:线程池创建时会初始化固定数量的线程。这些线程启动后,会不断从任务队列中获取任务并执行。当一个任务执行完毕,线程不会销毁,而是再次从任务队列中获取新任务,从而实现线程复用。
资源释放避免资源泄漏
为了避免长时间处理任务后资源(如数据库连接、文件句柄等)泄漏,需要确保在任务完成后正确释放资源。可以使用try - finally
块或Java 7引入的try - with - resources
语句(适用于实现了AutoCloseable
接口的资源)。
以下是使用数据库连接(以JDBC为例)的代码示例:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolResourceManagement {
private static final String URL = "jdbc:mysql://localhost:3306/mydb";
private static final String USER = "root";
private static final String PASSWORD = "password";
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
executorService.submit(new DatabaseTask());
}
executorService.shutdown();
}
static class DatabaseTask implements Runnable {
@Override
public void run() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = DriverManager.getConnection(URL, USER, PASSWORD);
String sql = "SELECT * FROM users";
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString("username"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (resultSet != null) resultSet.close();
if (preparedStatement != null) preparedStatement.close();
if (connection != null) connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
在上述代码中,DatabaseTask
类实现了Runnable
接口,在run
方法中进行数据库操作。通过try - finally
块,确保无论数据库操作是否成功,都能正确关闭ResultSet
、PreparedStatement
和Connection
,从而避免资源泄漏。
如果使用Java 7及以上版本,对于实现了AutoCloseable
接口的资源,可以使用try - with - resources
语句,代码会更加简洁:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolResourceManagementTryWithResources {
private static final String URL = "jdbc:mysql://localhost:3306/mydb";
private static final String USER = "root";
private static final String PASSWORD = "password";
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
executorService.submit(new DatabaseTask());
}
executorService.shutdown();
}
static class DatabaseTask implements Runnable {
@Override
public void run() {
String sql = "SELECT * FROM users";
try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
System.out.println(resultSet.getString("username"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
在这个示例中,try - with - resources
语句会自动在代码块结束时关闭Connection
、PreparedStatement
和ResultSet
,进一步简化了资源管理并确保资源不会泄漏。