对象池化工具commons-pool

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/j16421881/article/details/78764287

  关于对象池的概念这里不做过多解释,除了用来缓存数据库连接java.sql.Connection这种重量级对象也能用于其他场景。初始化对象的代价高,就值得池化。池化的一个代价是被重用的对象会在堆中停留很长时间。如果有大量对象存在于堆中,那用来创建新对象的空间就少了,因为GC 操作会更为频繁。
  以SimpleDateFormat 为例,这是 Java 中常用的一个类,用于解析和格式化日期字符串。
  但是 SimpleDateFormat 在多线程环境中并不是线程安全的。详见这位仁兄的 SimpleDateFormat 的线程安全问题与 ThreadLocal

  实现线程安全的一种思路是用ThreadLocal进行安全变量的副本。

 static ThreadLocal<SimpleDateFormat> format1 = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd");
    }
};

public String formatDate(Date date) {
    return format1.get().format(date);
}

  但是维持变量副本的资源也是需要消耗资源的。尽管ThreadLocal提供了remove方法以便在请求结束后释放副本,但若在请求结束的时候崩溃副本没有得到释放,将会给内存造成极大的压力。为了应对这种情况我们可以采用jdbc连接池的思想,把对象放入对象池工具里面,用"pool"来约束对象的创建与销毁。
  首先引入Apache commons-pool依赖

		<dependency>
			<groupId>commons-pool</groupId>
			<artifactId>commons-pool</artifactId>
			<version>1.6</version>
		</dependency>

接口的声明

//接口
import java.util.Date;
public interface FormattingService {
  String format(Date date);
  void setPattern(String pattern);
}

实现类

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;

public class PooledFormattingService implements FormattingService {

  // 对象池的实现 
  GenericObjectPool<SimpleDateFormat> dateFormatsPool;

  private static AtomicInteger count = new AtomicInteger(0);

  String pattern;
  
  public PooledFormattingService() {
  // 对象池工厂
    PoolableObjectFactory factory = new BasePoolableObjectFactory() {
      @Override
      public Object makeObject() throws Exception {
        System.out.println("创建新对象"+(count.incrementAndGet()));
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      }
    };

    dateFormatsPool = new GenericObjectPool(factory);
    // 这里设置创建新对象的最大数目
    dateFormatsPool.setMaxActive(10);
  }

  public String format(Date date) {
    try {
      SimpleDateFormat dateFormat =  this.dateFormatsPool.borrowObject();
      try {
        return dateFormat.format(date);
      } finally {
        this.dateFormatsPool.returnObject(dateFormat);
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public void setPattern(final String pattern) {
    PoolableObjectFactory factory = new BasePoolableObjectFactory() {
      @Override
      public Object makeObject() throws Exception {
        return new SimpleDateFormat(pattern);
      }
    };
    this.dateFormatsPool = new GenericObjectPool(factory);
  }

}

测试

import java.util.Date;

public class Mytest {

  public static void main(String[] args) {
    PooledFormattingService pooledFormattingService = new PooledFormattingService();
     //创建20个线程去调用SimpleDateFormat
     //由于对象池为10,SimpleDateFormat最多创建10个
    for (int i = 0; i < 20; i++) {
      new Thread(() -> {
        pooledFormattingService.format(new Date());
      }).start();

    }
  }
}

核心实现都在 org.apache.commons.pool.impl.GenericObjectPool里面
这里只展示几个关键参数

maxActive: 链接池中最大连接数,默认为8.
maxIdle: 链接池中最大空闲的连接数,默认为8.
minIdle: 连接池中最少空闲的连接数,默认为0.
maxWait: 当连接池资源耗尽时,调用者最大阻塞的时间,超时将抛异常。默认永不超时.
minEvictableIdleTimeMillis: 连接空闲的最小时间,达到此值后空闲连接将可能会被移除。
softMinEvictableIdleTimeMillis: 连接空闲的最小时间,达到此值后空闲链接将会被移除
numTestsPerEvictionRun: 对于“空闲链接”检测线程而言,每次检测的链接资源的个数。默认为3.

猜你喜欢

转载自blog.csdn.net/j16421881/article/details/78764287