面试题答案
一键面试可能遇到的问题
- 资源竞争:多个线程同时请求对象池中的对象时,可能会发生竞争,导致性能下降。例如,线程A和线程B同时尝试从对象池中获取对象,可能会在获取对象的操作上等待。
- 对象状态不一致:如果对象在使用后未正确重置状态,不同线程使用对象时可能会得到错误的结果。比如一个用于数据库连接的对象,上一个线程使用后未关闭连接,下一个线程获取后直接使用可能导致数据混乱。
- 对象池耗尽:高并发情况下,对象池中的对象可能被快速耗尽,后续线程请求对象时无可用对象,导致线程等待甚至系统崩溃。
优化方法
- 使用线程安全的数据结构:例如使用
ConcurrentLinkedQueue
来存储对象池中的对象,它是线程安全的队列,能有效减少资源竞争。 - 对象状态管理:在对象被放回对象池时,确保对象状态被正确重置。可以在对象类中定义一个
reset
方法来完成此操作。 - 动态调整对象池大小:根据系统负载动态调整对象池的大小,避免对象池耗尽。可以使用
Semaphore
来控制对象的获取和释放,当对象池耗尽时,通过增加对象数量来满足需求。
关键代码片段
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
class ObjectPool<T> {
private final ConcurrentLinkedQueue<T> pool;
private final Semaphore semaphore;
public ObjectPool(int initialSize, int maxSize) {
pool = new ConcurrentLinkedQueue<>();
semaphore = new Semaphore(initialSize, true);
for (int i = 0; i < initialSize; i++) {
pool.add(createObject());
}
}
private T createObject() {
// 创建对象的逻辑,例如创建数据库连接对象
// 这里假设创建一个简单的字符串对象
return (T) "new object";
}
public T borrowObject() throws InterruptedException {
semaphore.acquire();
T object = pool.poll();
if (object == null) {
object = createObject();
}
return object;
}
public void returnObject(T object) {
if (pool.size() < semaphore.availablePermits()) {
pool.add(object);
semaphore.release();
}
}
}
使用示例:
public class Main {
public static void main(String[] args) {
ObjectPool<String> objectPool = new ObjectPool<>(5, 10);
Thread thread1 = new Thread(() -> {
try {
String obj = objectPool.borrowObject();
System.out.println("Thread 1 borrowed: " + obj);
// 使用对象
objectPool.returnObject(obj);
System.out.println("Thread 1 returned: " + obj);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread thread2 = new Thread(() -> {
try {
String obj = objectPool.borrowObject();
System.out.println("Thread 2 borrowed: " + obj);
// 使用对象
objectPool.returnObject(obj);
System.out.println("Thread 2 returned: " + obj);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread2.start();
}
}