0

これが基本的なものである場合は申し訳ありませんが、答えがわかりません。基本的に、ThreadPoolExecutor を使用していくつかのスレッドを実行し、10 個のスレッドを起動しています。各スレッドがその存続期間中、サーバーへの独自の接続を確立するようにします。可能であれば、このコードをどこに配置すればよいですか?

コード例:

class DoWork implements Runnable{

    protected String[] data = null; 

    public DoWork(String[] data) {
        // get the data each thread needs to work
        this.data = data;
    }

    public void run() {
        // Do the work here

    }

}

私の理解では、作業キューに項目がありThreadPoolExecutor、10 個のスレッドを維持し、作業が完了すると終了します。この構造のどこかに接続情報を追加できる場所はありますか? メソッドでそれを実行したくありません。これは、DoWork作業単位ごとに行われるためです (したがって、作業キュー内のアイテムと同じ数の接続を開くと、何千もの可能性があり、試したときにタイムアウトが発生する可能性があります)。クラス宣言とメソッドの間に入れても、何もしないように見えました(ただし、間違っている可能性があります)。

これを達成する方法のアイデアはありますか?

更新: 100% 必要ではありませんが、終了時に何かを実行する方法があるかどうか興味があります (おそらく、タイムアウトするのを待つ代わりに、サーバーへの接続を閉じることができます)。

4

4 に答える 4

5

ThreadLocalを使用して、各スレッドの接続を保存できます。

public class ConnectionProvider {
    private static final ThreadLocal<Connection> threadLocalConnection = 
         new ThreadLocal<Connection>() {
             @Override 
             protected Connection initialValue() {
                 // TODO create and return the connection
             }
         };

    public static Connection getConnection() {
        return threadLocalConnection.get();
    }
}

または、接続を複数のスレッドで(異なる時間に)使用できる場合は、接続のプールを作成できます。runメソッドは、プールから接続を取得し(動的に作成し、作成された接続のセットに追加することはできません)、使用が終了したらプールに解放します(finallyブロック内)。これにより、接続を他のタスクで使用できるようになります。これには、必要な接続の数をスレッドプール内のスレッドの数よりも潜在的に少なくするという利点があります。

于 2012-04-29T14:34:45.273 に答える
1

独自のスレッド ファクトリを作成し、それをパラメーターとしてスレッド プール コンストラクターに渡します。スレッド ファクトリによって作成されたスレッドは、メソッド run() を次のようにオーバーライドする必要があります。

public void run() {
  connectToServer();
  super.run();
}

問題は、その接続を誰がどのように使用するかです。スレッドプールに提供されるすべてのジョブが、実行中のスレッドによって作成された接続を使用する必要があることを意味する場合は、その接続を ThreadLocal として保存します。

于 2012-04-29T14:39:32.330 に答える
1

CLIプロセスのスレッドプールでの私の他の回答から適応

これにより、引き出し可能な接続プールが作成されます。これにより、接続がスレッドごとに上下するのを防ぐことができます。ただし、これは、どのスレッドがどの接続を使用するかが問題でない場合にのみ機能します。問題がある場合は、このコードを調整するか、他の誰かが提案した ThreadLocal を使用して、スレッドが終了したときにフックする必要があります。

新しい作業項目がキューに入れられると、スレッドは接続プールに接続を要求します。利用できない場合は、新しいものを作成します。利用可能な場合、接続がまだ有効であることを確認し、そのオブジェクトを返します。作業項目が終了すると、それを接続プールに戻すことができます。

public class StackOverflow_10037379_jdk6 {

    private static Logger sLogger = Logger.getLogger(StackOverflow_10372827_jdk6.class.getName());           

    public static class ConnectionPoolableObjectFactory extends BasePoolableObjectFactory<Connection> {

        public ConnectionPoolableObjectFactory() {

        }

        @Override
        public Connection makeObject() throws Exception {                
            Connection connection = // createConnection
            return connection;
        }

        @Override
        public boolean validateObject(Connection connection) {
            return connection.isValid();
        }

        @Override
        public void destroyObject(Connection connection) throws Exception {
            connection.close();
        }

        @Override
        public void passivateObject(Connection connection) throws Exception {

        }
    }

    public static class WorkItem implements Runnable {

        private ObjectPool<Connection> mPool;
        private String mWork;

        public CLIWorkItem(ObjectPool<Connection> pool, String work) {
            mPool = pool;
            mWork = work;
        }

        @Override
        public void run() {
            Connection connection = null;
            try {
                connection = mPool.borrowObject();
                // do stuff with connection
            } catch (Exception ex) {
                sLogger.log(Level.SEVERE, null, ex);
            } finally {
                if (connection != null) {
                    try {
                        // Seriously.. so many exceptions.
                        mPool.returnObject(connection );
                    } catch (Exception ex) {
                        sLogger.log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {

        // Change the 5 to 20 in your case. 
        ObjectPool<Connection> pool =
                new GenericObjectPool<Connection>(
                new ConnectionPoolableObjectFactory(), 5);

        BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(100, true);

        ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 20, 1, TimeUnit.HOURS, queue);

        // print some stuff out.
        executor.execute(new WorkItem(pool, "Message 1\r\n"));
        executor.execute(new WorkItem(pool, "Message 2\r\n"));
        executor.execute(new WorkItem(pool, "Message 3\r\n"));
        executor.execute(new WorkItem(pool, "Message 4\r\n"));
        executor.execute(new WorkItem(pool, "Message 5\r\n"));
        executor.execute(new WorkItem(pool, "Message 6\r\n"));
        executor.execute(new WorkItem(pool, "Message 7\r\n"));
        executor.execute(new WorkItem(pool, "Message 8\r\n"));
        executor.execute(new WorkItem(pool, "Message 9\r\n"));
        executor.execute(new WorkItem(pool, "Message 10\r\n"));
        executor.execute(new WorkItem(pool, "Message 11\r\n"));

        executor.shutdown();
        executor.awaitTermination(4000, TimeUnit.HOURS);

        pool.close();
    }
}
于 2012-04-29T14:42:57.650 に答える
1

接続プールを使用する方が簡単ではないでしょうか? 各タスクは、開始時にプールから接続を取得し、終了時にそれを返すだけです。そうすれば、スレッドよりも多くの接続を作成する必要がなくなり、すべてのタスクが終了した後に接続プール (およびそのすべての接続) を簡単に破棄できます。

于 2012-04-29T14:43:43.803 に答える