6

外部の非スレッド セーフ ライブラリを自分の Web プロジェクトに統合しようとしました。クライアント スレッドごとにこのオブジェクトのインスタンスを作成するにはコストがかかりすぎることがわかりました。

その結果、次のプロパティを持つオブジェクト プールを作成したいと考えています。

  1. 動的オブジェクト作成。プール内のオブジェクトは、コンストラクターで作成する代わりに動的に作成されます。プールは最初は空で、クライアント スレッドがリソース オブジェクトを取得すると、プールはオンデマンドで新しいリソースを作成できます。作成されたオブジェクトの数がプールのサイズに達すると、その後、新しいクライアント スレッドはブロックされ、他のスレッドがリソースをリサイクルするのを待ちます。
  2. プールは公平である必要があり、公平性により、最初に要求したスレッドが最初に取得したスレッドになることが保証されます。そうしないと、一部のスレッドが永遠に待機する可能性があります。

どうすればいいですか?実用的な例があれば幸いです。

4

1 に答える 1

17

この質問と解決策はhttps://www.dbtsai.com/blog/2013/java-concurrent-dynamic-object-pool-for-non-thread-safe-objects-using-blocking-queue/から要約されています

並行オブジェクト プールは Java 並行パッケージのブロッキング キューによって構築でき、ArrayBlockingQueue は必要な公平性もサポートします。この実装では、ReentrantLock を使用して、プールに新しいオブジェクトを作成できるかどうかを制御します。その結果、動的でない作成モード、つまりコンストラクターですべてのオブジェクトを作成する場合、このロックは常にロックされます。動的作成モードでは、毎回 1 つのオブジェクトしか作成できないため、このオブジェクトを取得する別のスレッドが存在する場合、削除をブロックしている pool.take() からオブジェクトを取得し、新しい利用可能なスレッドを待ちます。キュー内のリソース。

    public abstract class ResourcePool {
        private final BlockingQueue pool;
        private final ReentrantLock lock = new ReentrantLock();
        private int createdObjects = 0;
        private int size;
     
        protected ResourcePool(int size) {
            this(size, false);
        }
     
        protected ResourcePool(int size, Boolean dynamicCreation) {
            // Enable the fairness; otherwise, some threads
            // may wait forever.
            pool = new ArrayBlockingQueue<>(size, true);
            this.size = size;
            if (!dynamicCreation) {
                lock.lock();
            }
        }
     
        public Resource acquire() throws Exception {
            if (!lock.isLocked()) {
                if (lock.tryLock()) {
                    try {
                        ++createdObjects;
                        return createObject();
                    } finally {
                        if (createdObjects < size) lock.unlock();
                    }
                }
            }
            return pool.take();
        }
     
        public void recycle(Resource resource) throws Exception {
            // Will throws Exception when the queue is full,
            // but it should never happen.
            pool.add(resource);
        }
     
        public void createPool() {
            if (lock.isLocked()) {
                for (int i = 0; i < size; ++i) {
                    pool.add(createObject());
                    createdObjects++;
                }
            }
        }
     
        protected abstract Resource createObject();
    }

次の例では、リソース プール内の 2 つの DataTimeFormat オブジェクトを同時に取得する 5 つのクライアント スレッドがあり、これらのクライアント スレッドは合計 30 の計算を実行します。

    class DataTimeFormatResourcePool extends ResourcePool<SimpleDateFormat> {
 
    DataTimeFormatResourcePool(int size, Boolean dynamicCreation) {
        super(size, dynamicCreation);
        createPool();
    }
 
    @Override
    protected SimpleDateFormat createObject() {
        return new SimpleDateFormat("yyyyMMdd");
    }
 
    public Date convert(String input) throws Exception {
        SimpleDateFormat format = acquire();
        try {
            return format.parse(input);
        } finally {
            recycle(format);
        }
    }
}
 
public class ResourcePoolExample {
    public static void main(String args[]) {
        final DataTimeFormatResourcePool pool = new DataTimeFormatResourcePool(2, true);
 
        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return pool.convert("20130224");
            }
        };
 
        ExecutorService exec = Executors.newFixedThreadPool(5);
        List<Future<Date>> results = new ArrayList<>();
 
        for (int i = 0; i < 30; i++) {
            results.add(exec.submit(task));
        }
        exec.shutdown();
        try {
            for (Future<Date> result : results) {
                System.out.println(result.get());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
于 2013-02-25T00:07:26.610 に答える