솔직히 Pool 에 대해 제가 정확히 이해했는지 자신 없습니다. 아래 내용은 제 사견입니다.
Pool 은 미리 사용하려는 양 만큼의 버퍼를 할당해 놓고 객체를 사용하고 사용한 객체는 다시 버퍼에 넣고 재활용하는 방식의 방법입니다.
이런 방식의 장점으로는 버퍼를 재활용함으로 인해 객체 할당 및 제거에 드는 시간을 없앨 수 있다는 점이 있겠습니다.
Pool.java
- queue 가 두개 필요합니다. 유휴 버퍼와 사용 가능 버퍼로 나눕니다.
- 유휴 버퍼는 미리 빈 객체들로 원하는 갯수 만큼 채워 넣습니다.
- 사용 가능 버퍼에는 유휴 버퍼에서 얻은 사용 객체로 하나씩 채워지게 됩니다.
- 사용 가능 버퍼를 다 사용하고 나면 다시 유휴 버퍼로 옮겨 넣음으로써 나중에 다시 사용 가능하게 됩니다.
소스 코드 :
package pool.test;
import java.util.concurrent.LinkedBlockingQueue;
/**
*
* @param <T>
*/
public class Pool<T> {
private LinkedBlockingQueue<T> free = new LinkedBlockingQueue<T>();
private LinkedBlockingQueue<T> work = new LinkedBlockingQueue<T>();
/**
*
* @param creator
* @param count
*/
public Pool(PoolObjectCreator<T> creator, int count) {
for (int i = 0;i < count; i++) {
free.add(creator.create());
}
}
/**
*
* @return
*/
public final T acquire() {
return free.size() > 0 ? free.remove() : null;
}
/**
*
* @param item
*/
public final void enqueue(T item) {
work.add(item);
}
/**
*
* @return
*/
public final T dequeue() {
return work.size() > 0 ? work.remove() : null;
}
/**
*
* @param item
*/
public final void release(T item) {
free.add(item);
}
/**
*
* @param <T>
*/
public static interface PoolObjectCreator<T> {
public T create();
}
}
아래 내용은 Pool 사용 예제 입니다.- Producer 스레드에서는 1초 마다 pool 에 데이터를 넣습니다.
- Consumer 스레드에서는 pool 에서 데이터를 받아서 화면에 값을 출력합니다.
Main.java :
package pool.test;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
*
*/
public class Main {
private Consumer consumer;
private Producer producer;
/**
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
Main main = new Main();
main.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
reader.readLine();
main.stop();
System.out.println("Done");
}
/**
*
*/
public void start() {
Pool<Container> pool = new Pool<Container>(new Pool.PoolObjectCreator<Container>() {
@Override
public Container create() {
return new Container();
}
} , 10);
producer = new Producer(pool);
consumer = new Consumer(pool);
producer.start();
consumer.start();
}
/**
*
*/
public void stop() {
producer.interrupt();
consumer.interrupt();
}
/**
*
*/
public class Container {
public int x;
}
/**
*
*/
public class Producer extends Thread {
private Pool<Container> pool;
public Producer(Pool<Container> pool) {
this.pool = pool;
}
@Override
public void run() {
super.run();
try {
System.out.println("Producer :: start");
int count = 0;
Container container = null;
while (!Thread.interrupted()) {
if ((container = pool.acquire()) != null) {
container.x = count++;
pool.enqueue(container);
Thread.sleep(1000);
} else {
Thread.sleep(10);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Producer :: done");
}
}
}
/**
*
*/
public class Consumer extends Thread {
private Pool<Container> pool;
public Consumer(Pool<Container> pool) {
this.pool = pool;
}
@Override
public void run() {
super.run();
try {
System.out.println("Consumer :: start");
Container container = null;
while (!Thread.interrupted()) {
if ((container = pool.dequeue()) != null) {
System.out.printf("x : %d\n", container.x);
pool.release(container);
} else {
Thread.sleep(10);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Consumer :: done");
}
}
}
}
