CountDownLatch场景:CountDownLatch 的作用就是 允许 count 个线程阻塞在一个地方,直至所有线程的任务都执行完毕。之前在项目中,有一个使用多线程读取多个文件处理的场景,我用到了 CountDownLatch 。
import cn.hutool.core.thread.ThreadUtil;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
public class CountDownLatchExample {
// 处理文件的数量
private static final int threadCount = 6;
public static void main(String[] args) throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int threadnum = i;
ThreadUtil.execute(()->{
try {
//处理文件的业务操作
} finally {
//表示一个文件已经被完成
countDownLatch.countDown();
}
});
countDownLatch.await();
}
//改进1
//是 CompletableFuture 吧!这个确实可以通过这个类来改进。
//Java8 的 CompletableFuture 提供了很多对多线程友好的方法,
//使用它可以很方便地为我们编写多线程程序,
//什么异步、串行、并行或者等待所有线程执行完任务什么的都非常方便
CompletableFuture<Void> task1 =
CompletableFuture.supplyAsync(()->{
//自定义业务操作
return null;
});
CompletableFuture<Void> task6 =
CompletableFuture.supplyAsync(()->{
//自定义业务操作
return null;
});
CompletableFuture<Void> headerFuture= CompletableFuture.allOf(task1,task6);
try {
headerFuture.join();
} catch (Exception ex) {
}
//改进2
//不过代码还可以接续优化,当任务过多的时候,
//把每一个 task 都列出来不太现实,可以考虑通过循环来添加任务
//文件夹位置
List<String> filePaths = Arrays.asList("");
// 异步处理所有文件
List<CompletableFuture<String>> fileFutures = filePaths.stream()
.parallel().map(filePath -> doSomeThing(filePath))
.collect(Collectors.toList());
// 将他们合并起来
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
fileFutures.toArray(new CompletableFuture[fileFutures.size()])
);
}
private static CompletableFuture<String> doSomeThing(String filePath) {
return null;
}
}
commons-pool2场景:在这种对象的初始化工作包含了一些费时的操作(例如,从一台位于20,000千米以外的主机上读出一些数据或者频繁创建对象)的时候,尤其是这样。在需要大量生成这样的对象的时候,就可能会对性能造成一些不可忽略的影响。要缓解这个问题,除了选用更好的硬件和更棒的虚拟机以外,适当地采用一些能够减少对象创建次数的编码技巧,也是一种有效的对策。对象池化技术(Object Pooling)就是这方面的著名技巧,而Jakarta Commons Pool组件则是处理对象池化的得力外援。Commons Pool组件提供了一整套用于实现对象池化的框架,以及若干种各具特色的对象池实现,可以有效地减少处理对象池化时的工作量,为其它重要的工作留下更多的精力和时间Apache Common-pool2完全重写了的对象池的实现,显著的提升了性能和可伸缩性,特别是在高并发加载的情况下。
HttpClient案例:
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
public class PooledHttpClientFactory implements PooledObjectFactory<HttpClient> {
//构造一个封装对象
@Override
public PooledObject<HttpClient> makeObject() {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
return new DefaultPooledObject<>(httpClient);
}
//销毁对象
@Override
public void destroyObject(PooledObject<HttpClient> pooledObject) {
//不处理
}
//验证对象是否可用
@Override
public boolean validateObject(PooledObject<HttpClient> pooledObject) {
return true;
}
//激活一个对象,使其可用用
@Override
public void activateObject(PooledObject<HttpClient> pooledObject) {
//不处理
}
//钝化一个对象,也可以理解为反初始化
@Override
public void passivateObject(PooledObject<HttpClient> pooledObject) {
//不处理
}
}
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.poi.util.IOUtils;
@Slf4j
public class CommonsPoolExample {
public static void main(String[] args) {
GenericObjectPoolConfig httpClientPoolConfig = new GenericObjectPoolConfig();
httpClientPoolConfig.setMaxTotal(100);
httpClientPoolConfig.setMaxIdle(10);
PooledHttpClientFactory httpClientFactory = new PooledHttpClientFactory();
GenericObjectPool<HttpClient> httpClientPool = new GenericObjectPool<>(httpClientFactory, httpClientPoolConfig);
try {
HttpClient httpClient = httpClientPool.borrowObject();
RequestBuilder requestBuilder = RequestBuilder.get("https://www.baidu.com");
requestBuilder.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36");
HttpUriRequest httpUriRequest = requestBuilder.build();
HttpClientContext httpClientContext = new HttpClientContext();
HttpResponse httpResponse = httpClient.execute(httpUriRequest, httpClientContext);
byte[] contentBytes = IOUtils.toByteArray(httpResponse.getEntity().getContent());
log.info("获取的网页源码:" + new String(contentBytes, "utf-8"));
httpClientPool.returnObject(httpClient);
httpClientPool.invalidateObject(httpClient);
} catch (Exception e) {
log.error("获取网页异常:{}", e);
}
}
}
优化new Object对象:
import lombok.Data;
@Data
public class TestObject {
private String name;
private boolean isActive;
}
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
/**
* TestObject 工厂类
*/
public class TestObjectFactory implements PooledObjectFactory<TestObject> {
/**
* /构造一个封装对象
*
* @return
*/
@Override
public PooledObject<TestObject> makeObject() {
return new DefaultPooledObject<>(new TestObject());
}
/**
* 销毁对象
*
* @param pooledObject
*/
@Override
public void destroyObject(PooledObject<TestObject> pooledObject) {
}
/**
* 验证对象是否可用
*
* @param pooledObject
* @return
*/
@Override
public boolean validateObject(PooledObject<TestObject> pooledObject) {
return pooledObject.getObject().isActive();
}
/**
* 激活一个对象,使其可用用
*
* @param pooledObject
*/
@Override
public void activateObject(PooledObject<TestObject> pooledObject) {
pooledObject.getObject().setActive(true);
}
/**
* 钝化一个对象,也可以理解为反初始化
*
* @param pooledObject
*/
@Override
public void passivateObject(PooledObject<TestObject> pooledObject) {}
}
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.AbandonedConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
public class TestObjectPool extends GenericObjectPool<TestObject> {
public TestObjectPool(PooledObjectFactory<TestObject> factory) {
super(factory);
}
public TestObjectPool(PooledObjectFactory<TestObject> factory, GenericObjectPoolConfig config) {
super(factory, config);
}
public TestObjectPool(PooledObjectFactory<TestObject> factory, GenericObjectPoolConfig config, AbandonedConfig abandonedConfig) {
super(factory, config, abandonedConfig);
}
}
/**
* 对象池配置
*/
@Configuration
@Data
public class PoolProperties {
/**
* 最大空闲
*/
private int maxIdle = 5;
/**
* 最大总数
*/
private int maxTotal = 20;
/**
* 最小空闲
*/
private int minIdle = 2;
/**
* 初始化连接数
*/
private int initialSize = 3;
}
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PreDestroy;
/**
* 对象池自动装配
*/
@EnableConfigurationProperties(PoolProperties.class)
@Configuration
public class PoolAutoConfiguration {
private final PoolProperties poolProperties;
private TestObjectPool pool;
@Autowired
public PoolAutoConfiguration(PoolProperties poolProperties) {
this.poolProperties = poolProperties;
}
@ConditionalOnClass({TestObjectFactory.class})
@Bean
protected TestObjectPool faceSDKPool() {
TestObjectFactory faceSDKFactory = new TestObjectFactory();
//设置对象池的相关参数
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxIdle(poolProperties.getMaxIdle());
poolConfig.setMaxTotal(poolProperties.getMaxTotal());
poolConfig.setMinIdle(poolProperties.getMinIdle());
poolConfig.setBlockWhenExhausted(true);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setTestWhileIdle(true);
poolConfig.setTimeBetweenEvictionRunsMillis(1000 * 60 * 30);
//一定要关闭jmx,不然springboot启动会报已经注册了某个jmx的错误
poolConfig.setJmxEnabled(false);
//新建一个对象池,传入对象工厂和配置
pool = new TestObjectPool(faceSDKFactory, poolConfig);
initPool(poolProperties.getInitialSize(), poolProperties.getMaxIdle());
return pool;
}
/**
* 预先加载testObject对象到对象池中
*
* @param initialSize 初始化连接数
* @param maxIdle 最大空闲连接数
*/
private void initPool(int initialSize, int maxIdle) {
if (initialSize <= 0) {
return;
}
int size = Math.min(initialSize, maxIdle);
for (int i = 0; i < size; i++) {
try {
pool.addObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@PreDestroy
public void destroy() {
if (pool != null) {
pool.close();
}
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Objects;
@Slf4j
public class CommonsPoolExample2 {
@Autowired
private TestObjectPool testObjectPool;
public void test() {
TestObject testObject = null;
try {
testObject = testObjectPool.borrowObject();
//省略业务代码...
} catch (Exception e) {
log.info("获取对象异常:{}",e);
} finally {
if (Objects.nonNull(testObject)) {
//最终归还对象到对象池
testObjectPool.returnObject(testObject);
}
}
}
}