この質問と解決策は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();
}
}
}