对象池模式(Object Pool Pattern)是一种创建模式(Creational Design Patterns)。对象池模式能够提升对象创建的性能。特别是当对象创建过程比较耗时时,事先将对象创建出来,缓存在对象池中。当需要时,直接从对象池中取出对象。在使用完毕后,将对象返还给对象池。因此,在使用时,无需重新创建新对象,节省对象创建的时间。
对象池模式的一个经典应用是数据库连接池应用。因为与数据库建立连接的过程非常复杂,较为耗时。使用数据库连接池技术,能大大提高数据库应用程序的性能。
在对象模式中有着3个参与方。
图一 对象池模式结构。
我们使用一个简单的例子来介绍对象池模式的使用方法。首先,我们定义一个CachedObject类,用于表示存放在对象池中的对象。
public class CachedObject {
}
类CachedObjectPool表示的是对象池。在构造函数中,创建一些对象,放在对象池中。所有的对象由一个链表保存维护。参数capacity表示的是初始缓存对象的个数。get()和release()方法分别从池中获得对象和将对象返回给对象池。
public class CachedObjectPool {
private List<CachedObject> cache = null;
public CachedObjectPool(int capacity) {
cache = new LinkedList<CachedObject>(capacity);
for (int i = 0; i < capacity; i++) {
cache.add(new CachedObject());
}
}
public CachedObject get() {
return cache.remove(0);
}
public void release(CachedObject obj) {
cache.add(obj);
}
}
最后,当开发人员需要使用对象时,只需要调用get()方法从对象池中获取即可。
public class CachedObjectPoolExample {
public static void main(String[] args) {
CachedObjectPool objectPool = new CachedObjectPool(5);
CachedObject obj = objectPool.get();
...
}
}
在Java应用程序中,常用的JDBC数据库连接池代码库有Apache Commons DBCP2、 C3P0、 Apache Tomcat JDBC和HikariCP。她们都能够提供较稳定的服务。如果读者对她们的使用方法感兴趣的话,可自行阅读其源代码。
在本小节中,我们将简要的介绍一下Java多线程程序设计中的一个重要的接口ExecutorService。在通常的情况下,开发人员会生成一个线程池,用来同时运行多个任务。线程池中的线程是共享的。开发人员可以指定线程池中线程的初始个数。在运行过程中,线程池也会根据任务量动态的调整线程的个数。更多ExecutorService接口的使用细节可参考小水滴的文章"线程池(Thread Pool)和ExecutorService接口"。
如下是一个常见的使用ExecutorService接口的例子。程序首先创建一个包含了3个线程的线程池,并执行一个Runnable对象。
public class ExecutorServiceExample {
public static void main(String[] args) {
// 创建一个ExecutorService对象
ExecutorService executor = Executors.newFixedThreadPool(3);
// 创建一个Runnable对象
Runnable runnable = ()->{return;};
// 一次只提交一个Runnable对象或者Callable对象
Future future1 = executor.submit(runnable);
}
}
在Executors类中,newFixedThreadPool()方法会创建一个ThreadPoolExecutor对象。
// OpenJDK 15
package java.util.concurrent;
public class Executors {
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
}
在ThreadPoolExecutor类中,它实现了ExecutorService接口。它使用队列workQueue来维护需要完成的任务。线程对象是保存在成员变量workers中的。workers是一个HashSet对象。在线程对象创建完成后,可用于执行各项任务。在默认情况下,只有当收到任务之后,才会创建出“核心线程(Core Thread)”。但是,开发人员可以使用prestartCoreThread()或者prestartAllCoreThreads()方法覆盖默认行为。
// OpenJDK 15
package java.util.concurrent;
public class ThreadPoolExecutor extends AbstractExecutorService {
...
private final BlockingQueue<Runnable> workQueue;
private final HashSet<Worker> workers = new HashSet<>();
}
在成员变量workers中,每一个元素是一个Worker对象。Worker是ThreadPoolExecutor的内部类,用于维护线程状态和当前运行的任务。因此,它有着一个成员变量thread。
// java.util.concurrent.THreadPoolExecutor.java from OpenJDK 15
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
...
final Thread thread;
Runnable firstTask;
...
}
本章介绍了对象池模式的结构和使用方法。在对象池模式下,对象会事先创建并缓存在对象池中。因此,在使用时,可以直接从对象池中申请一个未被使用的对象,从而节省了对象创建的时间。数据库连接池技术和线程池技术都是对象池技术的一种应用。
注册用户登陆后可留言