I'm struggling to figure out how to pool resources and I'm starting to suspect my threads maybe the problem(not 100% but been experimenting with it). The gist of what I'm trying to do is create a pool of channels to a server and then see if threads are using them. I've been successful at getting the number of channels to be created for as many items I'm uploading(i.e. its not pooling and just creating new channels in each thread) and successful at creating only one channel(i.e. not pooling or creating new channels as needed).
I was thinking maybe the way the threads are interacting with the pool is the problem so I tried to create newCachedThreadPool
so the threads don't die as long as there's work but when I do I get errors saying the channel being used as been closed. There is a destroyObject
method in my pool but I never call it so I don't understand why its being triggered(if I comment it out then it works but only creates one channel and upload is very very slow about 300 operations/second versus without threaded pool I get 30k/second). I suspect its terminating, is there any way to verify this and is there an alterative I can use if it is terminating?
Here's the code(ignore all the rabbitmq stuff, its just so I can monitor the results):
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.MessageProperties;
public class PoolExample {
private static ExecutorService executor_worker;
static {
final int numberOfThreads_ThreadPoolExecutor = 20;
executor_worker = Executors.newCachedThreadPool();
executor_worker = new ThreadPoolExecutor(numberOfThreads_ThreadPoolExecutor, numberOfThreads_ThreadPoolExecutor, 1000, TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>());
}
private static ObjectPool<Channel> pool;
public static void main(String[] args) throws Exception {
System.out.println("starting..");
ObjectPool<Channel> pool =
new GenericObjectPool<Channel>(
new ConnectionPoolableObjectFactory(), 50);
for (int x = 0; x<500000000; x++) {
executor_worker.submit(new MyRunnable(x, pool));
}
//executor_worker.shutdown();
//pool.close();
}
}
class ConnectionPoolableObjectFactory extends BasePoolableObjectFactory<Channel> {
Channel channel;
Connection connection;
public ConnectionPoolableObjectFactory() throws IOException {
System.out.println("hello world");
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
channel = connection.createChannel();
}
@Override
public Channel makeObject() throws Exception {
//channel = connection.createChannel();
return channel;
}
@Override
public boolean validateObject(Channel channel) {
return channel.isOpen();
}
@Override
public void destroyObject(Channel channel) throws Exception {
channel.close();
}
@Override
public void passivateObject(Channel channel) throws Exception {
//System.out.println("sent back to queue");
}
}
class MyRunnable implements Runnable{
protected int x = 0;
protected ObjectPool<Channel> pool;
public MyRunnable(int x, ObjectPool<Channel> pool) {
// TODO Auto-generated constructor stub
this.x = x;
this.pool = pool;
}
public void run(){
try {
Channel channel = pool.borrowObject();
String message = Integer.toString(x);
channel.basicPublish( "", "task_queue",
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes());
pool.returnObject(channel);
} catch (NoSuchElementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
p.s. I basically asked a few questions and read the documentation and tried to figure this out and along the way I may have gone totally in the wrong direction so if there's any problems you see or tips then please send them my way.
The plot thickens:
In the main method's for loop(where I submit the work to the threads) I added:
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
System.out.println(threadSet.size()); //number of threads
System.out.println(pool.getNumActive());
It shows me 25 threads(although I said 20) and 20 items in the pool. But when I look at the rabbitmq UI, I see one connection with only one channel. If I create channels and submit to the runnable then it creates many channels(but it never closes them). I don't understand what's going on and why the result is not as expected.