0

接続プール (JDBC 接続と SMPP 接続) を実装しています。よくテストされた接続プールがいくつかあることは知っていますが、自分で実装したいだけです。マルチスレッド環境で使用しています。これは私の個人的な関心事です。私の実装は次のようになります。ConcurrentLinkedQueue を作成し、接続をキューにプッシュします。スレッドが接続を要求するたびに、接続がキューからポップアウトされます。ジョブが完了すると、スレッドは接続をキューにプッシュします。私の接続ポーリング実装クラスは次のとおりです。

import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.log4j.Logger;
import org.jsmpp.bean.BindType;
import org.jsmpp.bean.NumberingPlanIndicator;
import org.jsmpp.bean.TypeOfNumber;
import org.jsmpp.session.BindParameter;
import org.jsmpp.session.SMPPSession;


public class SMPPConnectionPool {
    static ConcurrentLinkedQueue<SMPPSession> connectionPool = null;
    static Logger LOG = null;

    static 
    {
        LOG = LogManager.getLogger(SMPPConnectionPool.class);
        connectionPool= new ConcurrentLinkedQueue<SMPPSession>();
    }

    /* This method returns session from queue .If no sessions exist in the queue,then a new session will be created and returned.
     * This method use QueryGparams APi to read conenction related data from gparams
     * */
    public static SMPPSession getConenction()
    {
        SMPPSession session=connectionPool.poll();
        if(session!=null)
        {
            System.out.println("Thread "+Thread.currentThread().getName() +" got "+session.getSessionId());
            LOG.info("Thread "+Thread.currentThread().getName() +" got "+session.getSessionId());
            return session;
        }
        else
        {
            SMPPSession smppSession = new SMPPSession();
            try {
                String host = QueryGparams.getGparamAsString(NotificationConstants.SMSC_HOST);
                int port = QueryGparams.getGparamAsInteger(NotificationConstants.SMSC_PORT);
                String systemId = QueryGparams.getGparamAsString(NotificationConstants.SMSC_SYSTEM_ID);
                String password = QueryGparams.getGparamAsString(NotificationConstants.SMSC_PASSWORD);
                if(host == null || systemId == null || password == null || port == 0)
                {
                    String errorMessage = "Following parameters are null \n";
                    if(host == null) {
                        errorMessage = errorMessage + "host is null";
                    }
                    if(systemId == null) {
                        errorMessage = errorMessage + "systemId is null";
                    }
                    if(password == null) {
                        errorMessage = errorMessage + "password is null";
                    }
                    if(port == 0) { //TODO Need to change this if QueryGParams API will not return zero when port number is not specified 
                        errorMessage = errorMessage + "port is null";
                    }
                    throw new Exception(errorMessage);
                }
                smppSession
                .connectAndBind(host,port, new BindParameter(
                        BindType.BIND_TRX, systemId,
                        password, "",
                        TypeOfNumber.UNKNOWN,
                        NumberingPlanIndicator.UNKNOWN, null));
                LOG.info("Session has been created.Session id is "+smppSession.getSessionId());
            } catch (Exception e) {
                LOG.error(CommonUtilities.getExceptionString(e));
            }
            System.out.println("Thread "+Thread.currentThread().getName() +" got "+smppSession.getSessionId());
            LOG.info("Thread "+Thread.currentThread().getName() +" got "+smppSession.getSessionId());
            return smppSession;
        }
    }



    //This method pushes conenction back to queue ,to make it available for other threads. 
    public static void pushConenction(SMPPSession smppSession)
    {
        boolean isInserted=connectionPool.offer(smppSession);
        if(isInserted)
        {
            LOG.info("Pushed the conenction back to queue");
            System.out.println("Pushed the conenction back to queue");
        }
        else
        {
            LOG.info("Failed to push the session back to queue");
            System.out.println("Failed to push the session back to queue");
        }
    }
    public static void closeSessions()
    {
        while(connectionPool!=null && connectionPool.size()>0)
        {
            SMPPSession session=connectionPool.poll();
            session.unbindAndClose();
            LOG.info("Closed the session");
        }
    }

}

この実装の問題点を知りたいだけです.アドバイスをお願いします.JDBC接続プールの実装についても同じことをしたいです.

4

2 に答える 2

0

実装で見られる問題のいくつかは次のとおりです。

  1. connectAndBind に構成されたタイムアウトはありません。ネットワークの分割やパケット損失が発生した場合、getConnection 呼び出しが停止する可能性が高くなります。

  2. ネットワークが停止した場合、データ ソースとクライアント間の TCP 接続が切断される可能性があります。したがって、プールによって保持されている接続は古くなります。接続を「リフレッシュ」するメカニズムは存在しないようです。多くの接続プール フレームワークは、これに対処するために、バックグラウンドで、または接続をチェックアウトする直前に実行される te​​stConnections を提供します (もちろん、これにより getConnection 呼び出し全体にレイテンシが追加されます)。

于 2013-09-21T06:44:25.823 に答える
0

1) ブール isInserted=connectionPool.offer(smppSession); ConcurrentLinkedQueue は無制限であり、その offer() は常に true を返すため、後続の分析は意味がありません。API を参照

2) BlockingQueue を使用し、最大アクティブ スレッド数に達した場合に、アクティブ スレッドがプールに接続を返すのをスレッドが待機するようにします。

3) この方法で静的フィールドを初期化します

static ConcurrentLinkedQueue<SMPPSession> connectionPool = new ConcurrentLinkedQueue<SMPPSession>();
static Logger LOG = LogManager.getLogger(SMPPConnectionPool.class);

4) 不要な文字列連結を避けるために、このイディオムを使用できます

if (LOG.isInfoEnabled()) {
   LOG.info("Thread "+Thread.currentThread().getName() +" got "+smppSession.getSessionId());
}

5) これは怪しいと思われる

} catch (Exception e) {
    LOG.error(CommonUtilities.getExceptionString(e));
}
System.out.println("Thread "+Thread.currentThread().getName() +" got "+smppSession.getSessionId());

あなたは例外をキャッチし、すべてがOKであるかのように続行します

于 2013-09-21T06:40:50.230 に答える