0

假设有对象池的 Java 实现,并且对象成功连接了 TCP 套接字。

我在池级别(ConnectionFactory)保留一个“清理”线程,每 N 分钟检查一次池是否空闲了 M 分钟(即:最后一次访问是在 M 分钟之前,这里是 M>N)。

如果是这样,则关闭所有额外的套接字,直到池中只剩下核心数量的套接字。

现在我还需要跟踪并消除突然关闭的套接字。这似乎很重要,因为我可能会关闭所有正在工作的那些,并最终得到一个带有突然关闭的套接字的池(在另一端关闭)。

毫无疑问,现在我应该研究 Socket 级别而不是连接工厂级别。

我已经对“在 Java 中跟踪突然关闭的套接字”、“清理连接池”进行了研究,除非我们发送了一些 ACK 或 KeepAliveChecks(每个套接字),否则 Java 套接字 API 中没有任何内容。这意味着我需要定期在每个套接字上执行此操作。

什么是最好的方法(即:有没有其他方法)所以我最终可以将好人(连接良好的套接字)留在我的池中?

如何清理池中突然关闭的套接字?

4

2 回答 2

1

我不知道有任何其他方法可以检查套接字是否处于活动状态。您可以使用 TimerTask 发送例程 KeepAliveChecks 并删除未通过检查的套接字。

于 2014-08-15T07:51:18.280 回答
0

有意思,我昨天刚写了一个socket连接池。

  • 没有要检查的守护线程。
  • 它将检查被动以尝试建立连接
    • connection.isClosed 会检查socket状态,当然不可靠
    • 检查连接是否过期
  • 它将检查是否返回连接。您必须在使用异常时将连接标记为已关闭。

/** * @author:xingchaowang * @date: 8/14/2014. */

公共类 ConnectionPoolImpl 实现 ConnectionPool {

private volatile int minConnections;
private volatile int maxConnections;
private volatile long connectionTTL;
private volatile long leaseTimeout = 1000;

private AtomicInteger pending = new AtomicInteger(0);

private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();

private LinkedList<Connection> free = new LinkedList<Connection>();
private Set<Connection> leased = new HashSet<Connection>();

private ConnectionFactory connectionFactory;

public ConnectionPoolImpl(int minConnections, int maxConnections, long connectionTTL, long leaseTimeout, ConnectionFactory connectionFactory) {

    this.minConnections = minConnections;
    this.maxConnections = maxConnections;
    this.connectionTTL = connectionTTL;
    this.leaseTimeout = leaseTimeout;
    this.connectionFactory = connectionFactory;
}

@Override
public Connection lease() throws Exception {
    return lease(1000);
}

@Override
public Connection lease(long timeout) throws Exception {
    pending.incrementAndGet();
    lock.lock();
    try {
        Connection connection = null;
        Date deadLine = new Date(System.currentTimeMillis() + timeout);

        while (true) {
            long now = System.currentTimeMillis();

            //If the count of existing connections is less than minConnections, create new one and return.
            if (_connectionCount() < minConnections) {
                return _createAndLease();
            }

            //Try to get a connection from the free list.
            while ((connection = free.pollFirst()) != null) {
                if (connection.isClosed()) {
                    continue;
                } else if (connection.getCreatedTime() + connectionTTL < now) {
                    connection.close();
                }else{
                    leased.add(connection);
                    return connection;
                }
            }

            //Free list is empty, try to create new one if doesn't reach the upper limit maxConnections.
            if (_connectionCount() < maxConnections) {
                return _createAndLease();
            }

            condition.awaitUntil(deadLine);

            //Try to get again if doesn't reach the deadLine, or return by throwing a TimeoutException.
            if (deadLine.getTime() >= System.currentTimeMillis()) {
                throw new TimeoutException("Timeout waiting for connection");
            }
        }
    } finally {
        lock.unlock();
        pending.decrementAndGet();
    }
}

@Override
public void release(Connection connection) {
    lock.lock();
    try{
        long now = System.currentTimeMillis();

        leased.remove(connection);

        if (connection.isClosed()) {
            return;
        } else if (connection.getCreatedTime() + connectionTTL < now) {
            connection.close();
        }else{
            free.add(connection);
        }
    }finally {
        condition.signal();
        lock.unlock();
    }
}

@Override
public PoolStats poolStats() {
    return new PoolStats(leased.size(),free.size(),pending.get(),minConnections,maxConnections);
}

private int _connectionCount() {
    return free.size() + leased.size();
}

private Connection _createAndLease() throws Exception {
    Connection connection;
    connection = connectionFactory.create();
    leased.add(connection);
    return connection;
}

public int getMinConnections() {
    return minConnections;
}

public void setMinConnections(int minConnections) {
    this.minConnections = minConnections;
}

public int getMaxConnections() {
    return maxConnections;
}

public void setMaxConnections(int maxConnections) {
    this.maxConnections = maxConnections;
}

public long getConnectionTTL() {
    return connectionTTL;
}

public void setConnectionTTL(long connectionTTL) {
    this.connectionTTL = connectionTTL;
}

public long getLeaseTimeout() {
    return leaseTimeout;
}

public void setLeaseTimeout(long leaseTimeout) {
    this.leaseTimeout = leaseTimeout;
}

}

于 2014-08-15T08:13:49.087 回答