【问题标题】:How to keep fixed number of connections如何保持固定数量的连接
【发布时间】:2017-06-20 08:39:06
【问题描述】:

我是 Java 新手,但对一般编程并不陌生。

场景是我一次最多可以有 n 个连接,打开和关闭连接的成本非常高。

我想重用相同的 n 个连接并希望在 Collection 中保留一些东西。

当一个请求到来时,我拿起它连接,做我的工作并返回连接而不关闭。当下一个请求到来时,我会选择下一个可用的连接。

当所有连接都在使用并且请求到来时,我就等待连接可用。

什么是最干净的 java 解决方案。我不需要代码,我只需要一些想法来探索。可能是某些框架已经做到了,可能是某些 java 类已经提供了该功能。

任何想法都将不胜感激。

【问题讨论】:

  • 连接什么?
  • 像连接池数据库提供的东西......
  • 这些是到某些外部服务器的套接字连接
  • 所以,你有 n 个连接。放置一个分发连接的连接处理程序。如果没有可用的队列。

标签: java multithreading performance network-programming threadpool


【解决方案1】:

我建议您使用连接池。在此,如果您将 Connection 用于多个任务,请将它们分别编写并放入池中。 需要时从池中获取连接。完成后,将其推回池中。通过这种方式,连接将是线程安全的,并且可以避免不一致。 此外,打开和关闭连接会导致资源紧缩。

【讨论】:

    【解决方案2】:

    您可以使用具有固定线程数的执行器服务

    ExecutorService service = Executors.newFixedThreadPool(n);
    

    您可以创建一个 Connection 类,该类将创建一个连接对象并返回它

    class Connection implements Callable<Connection> {
    
        @Override
        public Connection call() {
            // Logic to get the connection
            return new Connection();
        }
    }
    

    然后提交任务并从池中获取 Connection 的 Future 对象。

    Future<Connection> future = service.submit(new Connection());
    Connection conn = future.get();
    

    【讨论】:

    • 仅仅为了创建连接而启动线程是很浪费的,而且这里没有任何东西可以将它们池化。
    【解决方案3】:

    使用 HTTP Core NIO 或 Netty 等框架来执行此操作。对于示例实例 HTTPCore NIO,您可以创建一个工作线程组以连接到后端,如下所示。

    ProxyConnPool connPool = createConnectionPool(connectingIOReactor);
    connPool.setMaxTotal(100);
    connPool.setDefaultMaxPerRoute(20);
    
    private static ProxyConnPool createConnectionPool(final ConnectingIOReactor connectingIOReactor)
                                                                                                        throws KeyManagementException,
                                                                                                        KeyStoreException,
                                                                                                        NoSuchAlgorithmException,
                                                                                                        CertificateException,
                                                                                                        FileNotFoundException,
                                                                                                        IOException {
            ProxyConnPool proxyConnPool = null;
    
            if (SECURE_BACKEND) {
                clientSSLContext =
                                   SSLUtil.createClientSSLContext(TRUST_STORE_LOCATION,
                                                                  TRUST_STORE_PASSWORD);
    
                BasicNIOConnFactory connectionFactory =
                                                        new BasicNIOConnFactory(
                                                                                clientSSLContext,
                                                                                null,
                                                                                ConnectionConfig.DEFAULT);
    
                proxyConnPool = new ProxyConnPool(connectingIOReactor, connectionFactory, 5000);
            } else {
                proxyConnPool = new ProxyConnPool(connectingIOReactor, ConnectionConfig.DEFAULT);
            }
    
            return proxyConnPool;
        }
    

    您可以找到我的 HTTP core NIO reverse proxyNetty reverse Proxy 的示例代码

    在 Netty 中,代码看起来与此类似。

    // Configure the bootstrap.
    EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    

    希望这会有所帮助。快乐编码!

    【讨论】:

      【解决方案4】:

      当一个请求到来时,我拿起它连接,做我的工作并返回连接而不关闭。当下一个请求到来时,我会选择下一个可用的连接。

      我会使用一个简单的BlockingQueue&lt;Connection&gt;,由您的所有线程共享。

      final BlockingQueue<Connection> connectionQueue = new LinkedBlockingQueue<Connection>();
      

      在您的应用程序开始时,您将打开一堆 Connection 对象并将它们添加到队列中。

      for (int i = 0; i < NUM_CONNECTIONS_TO_START; i++) {
          queue.put(new Connection());
      }
      

      当一个线程去获取一个连接时,它会从队列中得到一个Connection,如果没有立即可用的,则等待一个。在它使用Connection 之后,它会将它返回到队列中以供下一个线程使用。

      // this will wait if there are no connections available
      Connection connection = queue.take();
      try {
         useTheConnection(connection);
      } finally {
         // after we are done add it back to the queue
         queue.put(connection);
      }
      

      所有这一切的棘手部分是当您在套接字上遇到某种网络异常时。您的线程需要正确关闭Connection,然后将新线程添加到队列中。可能是这样的:

      // this will wait if there are no connections available
      Connection connection = queue.take();
      try {
         useTheConnection(connection);
      } catch (Exception e) {
         // assume the connection is bad
         try {
            connection.close();
         } catch (Exception e2) {
            // ignore any exceptions here
         }
         // start a new fresh connection to add back to our queue
         connection = new Connection();
      } finally {
         // after we are done add it back to the queue
         queue.put(connection);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-26
        • 2021-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-19
        • 1970-01-01
        相关资源
        最近更新 更多