CountDownLatch、commons-pool2、commons-pool

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);
            }
        }
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值