什么是池化技术
池化技术是一种很常见的编程技巧,目的在于提前创建如内存,对象,线程资源,降低程序运行时频繁的创建销毁带来的开销。常见的有线程池,内存池,对象池等。
池化技术如何提高性能,降低系统开销
在实际的应用中,程序经常需要创建对象,线程和分配内存。这些设计到系统调用,系统调用会导致程序从用户态到内核态的切换会比较耗时。有了池化技术,需要用到对应的线程,对象和内存时不需要再切换上下文之需要从相应的池中获取,也不需要销毁,用完归还即可。
线程池实现的原理
先启动若干线程让其处于休眠状态/当用户中的系统需要访问时,从线程池中拿出一个已建立的空闲的连接,使用完毕后不关闭连接而是归还到线程池中。
数据库连接池的重要配置:最大连接数和最小连接数
线程池的重要配置:核心线程数,最大线程数
对象池
写一个对象池需要考虑的:
- 对象池的结构 ,应该是维护两个固定大小的阻塞队列,两个队列一个是空闲一个使用。从空闲队列中获取对象后放入使用队列。使用完对象后不进行销毁而是放入空闲队列中 .
- 池的大小 ,池中最大放多少,当池满后怎么解决 .
- 池子怎么解决并发问题防止对一个对象的竞争
示例
1 对象池接口
public interface HousePool {
// 创建
House getHouse();
// 归还
void release(House po);
//初始化
void init();
}
具体实现
@Service
public class HousePoolImpl implements HousePool{
// 维护两个池子
private LinkedBlockingQueue<House> idle ;
private LinkedBlockingQueue<House> busy ;
//维护池中的对象数量
private final int maxSize = 10 ;
private AtomicInteger busySize = new AtomicInteger(0) ;
@Override
public void init() {
idle = new LinkedBlockingQueue<>();
busy = new LinkedBlockingQueue<>();
}
@Override
public House getHouse() {
// 创建对象池
House po = null;
po = idle.poll();
// 有空闲对象 直接用
if(po != null){
busy.offer(po);
return po;
}
// 未满 创建
if(busySize.get() < maxSize){
if(busySize.incrementAndGet() <= maxSize){
System.out.println("创建House");
po = new House();
busy.offer(po);
return po;
}
}
// 已满等待或超时报错
try {
idle.poll(10000, TimeUnit.MILLISECONDS);
if(po ==null){
throw new RuntimeException("超时");
}
busy.offer(po);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return po;
}
@Override
public void release(House po) {
busy.remove(po);
idle.offer(po);
}
}
初始化配置
@Configuration
public class PoolConfiguration {
@Bean
public HousePool housePool(){
HousePoolImpl housePool = new HousePoolImpl();
housePool.init();
return housePool;
}
}
代码解读:
为什么使用LinkedBlockingQueue作为对象池化的容器
1 容量可选:可以选择指定容量,也可以不指定,不指定时容量为Integer.MAX_VALUE。
2 公平性选择:可以选择是否公平地对等待的生产者和消费者进行排序。
3 阻塞操作:当队列为空时,消费者会被阻塞直到队列非空;当队列满时,生产者会被阻塞直到队列有空间。
4 线程安全。
如何解决多线程环境下对同一个空闲对象的竞争
private AtomicInteger busySize = new AtomicInteger(0) ;
if(busySize.get() < maxSize){
if(busySize.incrementAndGet() <= maxSize){
System.out.println("创建House");
po = new House();
busy.offer(po);
return po;
}
}
解决池满后等待问题
// 已满等待或超时报错
try {
idle.poll(10000, TimeUnit.MILLISECONDS);
if(po ==null){
throw new RuntimeException("超时");
}
busy.offer(po);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
测试
@Test
void testOrigin() {
housePool.init();
int i = 0 ;
while(i < 10){
House house = housePool.getHouse();
System.out.println("得到hosue");
housePool.release(house);
i++;
}
}
结果
可以看到对象只创建了一次,被使用了多次