文章目录
  1. 1. 对象池化技术
  2. 2. 实例
  3. 3. JDK中的对象池
    1. 3.1. String类
  4. 4. 用或不用?
  5. 5. 参考

当我们使用Mysql数据库的时候,经常会采取的一个策略是建立数据库连接池。因为我们知道新建一个数据库连接开销是比较大的,所以尽可能复用之前创建的连接。本文我们就自己去实现一个简单的,更具一般意义的对象池(数据库连接池是对象池的一种)。

对象池化技术

基本思想:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。用于充当保存对象的“容器”的对象,被称为“对象池”(Object Pool,或简称Pool)。

对于没有状态的对象(例如String),在重复使用之前,无需进行任何处理;对于有状态的对象(例如StringBuffer),在重复使用之前,就需要把它们恢复到等同于刚刚生成时的状态。由于条件的限制,恢复某个对象的状态的操作不可能实现了的话,就得把这个对象抛弃,改用新创建的实例了。

实例

下面我们就实现一个简单的包含Worker对象的对象池。

public class WorkerPool {
    private static final Logger logger = LoggerFactory.getLogger(WorkerPool.class);

    private int min_count, max_count;
    private Vector<WorkerWrapper> workers;

    public void setMin_count(int min_count) {
        this.min_count = min_count;
    }

    public void setMax_count(int max_count) {
        this.max_count = max_count;
    }

    public synchronized void createPool() {
        logger.info("create workerPool");

        if (workers == null) {
            workers = new Vector<>();
            createWorkers(min_count);
        }

    }

    public void createWorkers(int num) {
        logger.info("create " + num + " workers.");

        if (num <= 0)
            return;
        for (int i=0; i<num; i++) {
            if (max_count > 0 && workers.size() >= max_count) {
                break;
            }
            workers.add(newWorkerWrapper());
        }
    }

    private WorkerWrapper newWorkerWrapper() {
        logger.info("create a new workerWrapper.");

        WorkerWrapper workerWrapper = new WorkerWrapper();
        workerWrapper.worker = newWorker();
        workerWrapper.isBusy = false;
        return workerWrapper;
    }
    private Worker newWorker() {
        logger.info("create a new worker.");

        Worker worker = new GeTuiWorker();
        return worker;
    }

    public synchronized Worker getWorker() {
        logger.info("get worker.");

        if (workers == null)
            return null;

        Worker worker = getFreeWorker();

        while (worker == null) {
            wait(250);
            worker = getFreeWorker();
        }

        return worker;
    }

    private Worker getFreeWorker() {
        logger.info("get free worker.");

        Worker worker = findFreeWorker();

        if (worker == null) {
            createWorkers(1);
            worker = findFreeWorker();
            if (worker == null) {
                return null;
            }
        }
        return worker;
    }

    private Worker findFreeWorker() {
        logger.info("find free worker.");

        Worker worker = null;
        for (int i=0; i<workers.size(); i++) {
            if (!workers.get(i).isBusy) {
                worker = workers.get(i).worker;
                break;
            }
        }
        return worker;
    }

    public void returnWorker(Worker worker) {
        logger.info("return worker to pool.");

        if (worker == null || workers == null)
            return;

        for (int i=0; i<workers.size(); i++) {
            if (worker == workers.get(i).worker) {
                workers.get(i).isBusy = false;
                break;
            }
        }
    }

    public synchronized void refreshWorkerPools() {
        logger.info("refresh workerPool");
        if (workers == null)
            return;

        if (workers != null && workers.size() > 0) {
            for (int i=0; i<workers.size(); i++) {
                if (workers.get(i).isBusy) {
                    wait(5000);
                }

                workers.get(i).worker = newWorker();
                workers.get(i).isBusy = false;
            }
        }
    }

    public synchronized void closePool() {
        logger.info("close pool.");
        workers =null;
    }

    private void wait(int mSeconds) {
        try {
            Thread.sleep(mSeconds);
        } catch (InterruptedException e) {
        }
    }

    class WorkerWrapper {
        Worker worker;
        boolean isBusy;
    }
}

JDK中的对象池

在JDK5.0里,JVM在启动的时候会实例化9个对象池,这9个对象池分别用来存储8种基本数据类型的包装类对象和String对象。当我们直接用8种基本类型的包装类的对象或用双引号括起来一个字符串时,JVM就要在其对象池里面去找是否有一个相同的对象,如果有,就直接从对象池中拿这个现成的对象,如果没有,就在对象池里面创建一个新的对象。例如Integer对象池存放从-128–127之间的整数。

String类

创建String对象有两种方法:

String str1 = "xcbeyond";
String st2 = new String("xcbeyond");

这两种不同的创建方法是有差别的,第一种方式是在对象池中拿对象,第二种方式是直接在堆内存空间创建一个新的对象。因此,就有

System.out.println(str1==str2);//false

用或不用?

并非所有对象都适合拿来池化——因为维护对象池也要造成一定开销。对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略了。

总结:对象池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。

  1. 对于类似Point这样的轻量级对象,进行池化处理后,性能反而下降,因此不宜池化;
  2. 对于类似Hashtable这样的中量级对象,进行池化处理后,性能基本不变,一般不必池化(池化会使代码变复杂,增大维护的难度);
  3. 对于类似JPanel这样的重量级对象,进行池化处理后,性能有所上升,可以考虑池化。

基本上,只在重复生成某种对象的操作成为影响性能的关键因素的时候,才适合进行对象池化。如果进行池化所能带来的性能提高并不重要的话,还是不采用对象池化技术,以保持代码的简明,而使用更好的硬件和更棒的虚拟机来提高性能为佳。

参考

  1. Java对象池示例
文章目录
  1. 1. 对象池化技术
  2. 2. 实例
  3. 3. JDK中的对象池
    1. 3.1. String类
  4. 4. 用或不用?
  5. 5. 参考