什么是池化思想
在Java中,池化思想是一种通过创建和管理可重复使用的对象池来提高性能和资源利用率的编程思想。它的核心概念是在需要时从池中获取对象,而不是每次都创建新的对象,使用完毕后将对象返回到池中,以供其他代码复用。通过使用池化思想,可以避免不必要的资源创建和销毁操作,减少系统开销,提高程序的性能和可伸缩性。同时,池化思想还能够更好地管理和控制资源的使用,防止资源过度消耗和浪费。
编程中池化思想的体现
对象池
数据库连接池
http连接池
通过http连接池可以减少连接建⽴与释放的时间,提升http请求的性能
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory requestFactory){
return new RestTemplate(requestFactory);
}
@Bean
public ClientHttpRequestFactory httpRequestFactory(){
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
@Bean
public HttpClient httpClient(){
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
//设置连接池最大是500个连接
connectionManager.setMaxTotal(500);
//MaxPerRoute是对maxtotal的细分,每个主机的并发最大是300,route是指域名
connectionManager.setDefaultMaxPerRoute(300);
/**
* 只请求 xdclass.net,最大并发300
*
* 请求 xdclass.net,最大并发300
* 请求 open1024.com,最大并发200
*
* //MaxtTotal=400 DefaultMaxPerRoute=200
* //只连接到http://xdclass.net时,到这个主机的并发最多只有200;而不是400;
* //而连接到http://xdclass.net 和 http://open1024.com时,到每个主机的并发最多只有200;
* // 即加起来是400(但不能超过400);所以起作用的设置是DefaultMaxPerRoute。
*
*/
RequestConfig requestConfig = RequestConfig.custom()
//返回数据的超时时间
.setSocketTimeout(20000)
//连接上服务器的超时时间
.setConnectTimeout(10000)
//从连接池中获取连接的超时时间
.setConnectionRequestTimeout(1000)
.build();
CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.build();
return closeableHttpClient;
}
}
线程池
默认线程池: ThreadPoolTaskExecutor
存在的问题:
最⼤线程数:Integer.MAX_VALUE ( 21亿多)
队列使⽤LinkedBlockingQueue
容量是:Integer.MAX_VALUE
空闲线程保留时间:60s
线程池拒绝策略:AbortPolicy
自定义线程池
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
@Bean("threadPoolTaskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//线程池创建的核心线程数,线程池维护线程的最少数量,即使没有任务需要执行,也会一直存活
//如果设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
executor.setCorePoolSize(16);
//executor.setAllowCoreThreadTimeOut();
//阻塞队列 当核心线程数达到最大时,新任务会放在队列中排队等待执行
executor.setQueueCapacity(1024);
//最大线程池数量,当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
//任务队列已满时, 且当线程数=maxPoolSize,,线程池会拒绝处理任务而抛出异常
executor.setMaxPoolSize(64);
//当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
//允许线程空闲时间30秒,当maxPoolSize的线程在空闲时间到达的时候销毁
//如果allowCoreThreadTimeout=true,则会直到线程数量=0
executor.setKeepAliveSeconds(30);
//spring 提供的 ThreadPoolTaskExecutor 线程池,是有setThreadNamePrefix() 方法的。
//jdk 提供的ThreadPoolExecutor 线程池是没有 setThreadNamePrefix() 方法的
executor.setThreadNamePrefix("自定义线程池-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CallerRunsPolicy():交由调用方线程运行,比如 main 线程;如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行
// AbortPolicy():该策略是线程池的默认策略,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常。
// DiscardPolicy():如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常
// DiscardOldestPolicy():丢弃队列中最老的任务,队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
executor.initialize();
return executor;
}
}
面试题
A:请你说下 ThreadPoolTaskExecutor线程池有哪⼏个要参数,什么时候会创建线程
答:
1、查看核⼼线程池是否已满,不满就创建⼀条线程执⾏任务,否则执⾏第⼆步。
2、查看阻塞队列是否已满,不满就将任务存储在阻塞队列中,否则执⾏第三步。
3、查看线程池是否已满,即是否达到最⼤线程池数,不满就创建⼀条线程执⾏任务,否则就按照策略处理⽆法执⾏的任务。
B:⾼并发下核⼼线程怎么设置?
分IO密集还是CPU密集:
- CPU密集设置为跟核⼼数⼀样⼤⼩
- IO密集型设置为2倍CPU核⼼数