实现连接池:Java

cra*_*ace 15 java connection pooling

在我面临的一次采访中,我被要求实施连接池.所以方法是这样的:

  1. 创建一个ListHashMap
  2. 创建预定义的连接数
  3. 将它们添加到集合中.
  4. 现在,当调用类的ConnectionImpl getConnection()方法时,ConnectionPoolingImpl返回一个连接引用.

现在当有人返回connection(releaseConnection(ConnectionImpl O))时,如何确保当同一个应用程序再次尝试重用连接对象时,我的实现会引发异常?

可能已将相同的连接对象返回到新应用程序,并且应该能够使用它.

我的观点是在每个Connectionimpl对象的另一个数组类型的结构中维护一个标志变量,并将该变量设置为有效值.当用户返回连接对象时,我会将其设为无效值.对于我的每个操作ConnectionImpl,我都必须验证用户是否有有效标志.

你会对这种方法说些什么?

gus*_*afc 23

我不会从池中返回"真正的"连接对象,而是一个包装器,它提供连接生命周期的控制,而不是客户端.

假设您有一个非常简单的连接,您可以从中读取int值:

interface Connection {
    int read(); // reads an int from the connection
    void close(); // closes the connection
}
Run Code Online (Sandbox Code Playgroud)

从流中读取的实现可能如下所示(忽略异常,EOF处理等):

class StreamConnection implements Connection {
    private final InputStream input;
    int read(){ return input.read(); }
    void close(){ input.close(); }
}
Run Code Online (Sandbox Code Playgroud)

此外,让我们假设你有一个StreamConnection看起来像这样的s 池(再次,忽略异常,并发等):

class StreamConnectionPool {
    List<StreamConnection> freeConnections = openSomeConnectionsSomehow();
    StreamConnection borrowConnection(){ 
        if (freeConnections.isEmpty()) throw new IllegalStateException("No free connections");
        return freeConnections.remove(0); 
    }
    void returnConnection(StreamConnection conn){
        freeConnections.add(conn);
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的基本想法是好的,但我们不能确定返回的连接,我们不能确保它们不会关闭,然后返回,或者你不回这些来自其他来源完全的连接.

解决方案是(当然)另一层间接:创建一个返回包装器的池Connection,而不是在close()调用时关闭底层连接,将其返回到池:

class ConnectionPool {

    private final StreamConnectionPool streamPool = ...;

    Connection getConnection() {
        final StreamConnection realConnection = streamPool.borrowConnection();
        return new Connection(){
            private boolean closed = false;
            int read () {
                if (closed) throw new IllegalStateException("Connection closed"); 
                return realConnection.read();
            }
            void close() {
                if (!closed) {
                    closed = true;
                    streamPool.returnConnection(realConnection);
                }
            }
            protected void finalize() throws Throwable {
                try {
                    close();
                } finally {
                    super.finalize();
                }
            }
        };
    }

}
Run Code Online (Sandbox Code Playgroud)

ConnectionPool将是客户端代码所见到的唯一内容.假设它是唯一的所有者StreamConnectionPool,这种方法有几个优点:

降低复杂性和对客户端代码的影响最小 -自己打开连接,并使用池之间唯一的区别是,你使用一个工厂弄个ConnectionS(您可能已经这样做了,如果你使用依赖注入).最重要的是,您始终以相同的方式清理资源,即通过呼叫close().就像你不关心read它做什么一样,只要它能为你提供所需的数据,你就不在乎close()它做什么,只要它释放你声称的资源.您不必考虑此连接是否来自池.

防止恶意/不正确使用 - 客户端只能返回他们从池中检索到的资源; 他们无法关闭基础联系; 他们不能使用他们已经返回的连接......等等

"保证"返回资源 - 由于我们的finalize实施,即使所有对借用的引用Connection都丢失了,它仍然会返回到池中(或者至少有机会被退回).当然,连接将以这种方式保持不必要的时间 - 可能是无限期的,因为最终确定无法保证 - 但这只是一个很小的改进.


Chr*_*ett 5

我只是告诉他们我会使用H2附带的JdbcConnectionPool类(这里)(你可以把它复制出来).螺丝试图实现一个:)这可能是一个技巧问题.