java 对象池 博客_JAVA的那些池子 | 赵岩的博客

1、数据库连接池

JDBC在JDK中有一整套API,也就是接口。对于不同的数据库都有自己的实现。但是这些实现都是单个的连接,如果一个应用只有一个连接,那不能支持并发,如果一个操作就有一个连接,那连接的开销又非常大。

最好的办法就是一个线程一个连接,或者是总共建立30个连接,你用完了它用。这就是JDBC连接池的做法。

连接池要取出连接,再放回去,当连接不够的时候怎么办,连接闲置的时候怎么办,不同的连接池算法不一样,实现方式不一样,那连接池的开销也就是效率不一样。这个需要你自己去选择,不过连接池的实现原理大致都是相同的,就是实现JDK中的javax.sql.DataSource接口,通过javax.sql.DataSource.getConnection(),获取一个连接java.sql.Connection,也就是从池子里取出一个连接,这个Connection也由连接池去实现,在Connection.close()的时候,并没有关闭连接,而是把连接放回到池子中,从而达到池子的效果。

所以连接池的配置关键是DataSource的配置,等DataSource配好了,对连接池的使用,就像基础的JDBC连接一样使用。一般DataSource的配置都大同小异,都是那几个参数,参数的含义,网上都可以搜的到,下面是阿里巴巴的Druid数据库连接池的配置:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

value="${jdbc.driverClassName}"/>

value="${jdbc.timeBetweenEvictionRunsMillis}" />

value="${jdbc.minEvictableIdleTimeMillis}" />

value="${jdbc.validationQuery}" />

value="${jdbc.testWhileIdle}" />

value="${jdbc.defaultAutoCommit}"/>

2、HTTP连接池

HTTP连接,有一个keepalive的参数,只要你带了这个参数并且服务器支持这个参数,那么你就可以在timeout的时间内保持和服务器的连接,不断的发送请求,得到响应。这样你喝服务器的交互,就不用每次请求都去进行TCP的连接的三次握手等等,减少连接等待时间。所以如果你经常和一个服务器进行http交互的话,使用HTTP连接池是个不错的选择。

HTTP连接池的原理就是利用了keepalive的参数,保持几个或者多个服务器的连接,当你下次在有效的时间内去同一个服务器请求的时候,就会减少不小的开支。这就是为什么浏览器浏览一个网页,第一个请求可能很慢,后面的请求会很快,一方面可能是因为DNS初次解析的缘故,另一方面有可能就是keepalive参数的效果。

HTTP连接池的实现也有很多种,而且一般的HTTP包里的client都默认实现了连接池,你可以给它配置不同需求的连接池,这里示例apache的httpclient4X的连接池:org.apache.http.impl.conn.PoolingClientConnectionManager

1

2

3

4

5

6

7

8

9

10SchemeRegistry schemeRegistry = new SchemeRegistry();

schemeRegistry.register(

new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));

schemeRegistry.register(

new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));

PoolingClientConnectionManager connectionManager =

new PoolingClientConnectionManager(schemeRegistry);

connectionManager.setMaxTotal(maxConnections);

connectionManager.setDefaultMaxPerRoute(maxPerRoute);

把连接池管理器配给client即可

1

2DefaultHttpClient httpClient =

new DefaultHttpClient(connectionManager, params);

其中params 是你要配的其它参数,例如连接超时时间,请求超时时间等等。

3、线程池

如果你的任务需要并发执行,那么你就需要建立新的线程去执行,但是线程的建立是需要开销的,而且系统的线程数是有限制的,你不可能起无数个线程去执行任务的。如果你的线程的任务需要很大的内存或者带宽,起很多线程也是有限制的,所以你要用到线程池的概念。JDK就有丰富多彩的线程池实现,你直接可以使用,也就是java.util.concurrent.ExecutorService的实现类。concurrent字面上就是并发的意思。

最常用的就是java.util.concurrent.ThreadPoolExecutor。

你可以直接new出一个来就可以

1

2

3

4

5

6RejectedExecutionHandler rejectedExecutionHandler =

new ThreadPoolExecutor.AbortPolicy();

BlockingQueue queue= new LinkedBlockingQueue(queueCapacity);

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(

corePoolSize, maxPoolSize, keepAliveSeconds, TimeUnit.SECONDS,

queue, rejectedExecutionHandler);

当maxPoolSize个线程都用完了的时候,新添加的任务就会放到queue中,如果queue中都满了得话

就会按rejectedExecutionHandler

你选择的策略进行处理。所以你要根据你的业务量,合理安排pool的大小和queue的大小。

在使用的时候,只要向threadPool提交你的任务就可以了:

1

2

3

4

5

6threadPool.submit(new Runable(){

public void run()

{

}

});

4、普通对象池

如果你的一个对象的创建需要很大的开销,那么你需要使用对象池,创建一些对象放在池子里,用的时候取出来一个,不用的时候放回去。对象池也有现成的方案,那就是apache的commons-pool。

比较常用的是org.apache.commons.pool.impl.GenericObjectPool

你需要实现一个org.apache.commons.pool.PoolableObjectFactory接口中的makeObject,

activateObject, passivateObject, validateObject,

destroyObject方法。说明你的对象是如何实现的,是否是有效的对象,销毁这个对象需要说明操作等等。

然后new一个对象池就可以了,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17GenericObjectPool objectPool =

new PoolableObjectFactory(objectFactory);

//在使用的时候是这样的形式:

MyClass borrowObject = null;

try

{

borrowObject = objectPool.borrowObject();

//do any thing

}

finally

{

if(borrowObject != null)

{

objectPool.returnObject(borrowObject);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值