2626import java .util .HashMap ;
2727import java .util .Map ;
2828import java .util .concurrent .CopyOnWriteArrayList ;
29+ import java .util .concurrent .ExecutorService ;
2930import java .util .concurrent .TimeoutException ;
3031
3132import com .rabbitmq .client .AMQP ;
4445import com .rabbitmq .client .SaslConfig ;
4546import com .rabbitmq .client .SaslMechanism ;
4647import com .rabbitmq .client .ShutdownSignalException ;
48+ import com .rabbitmq .client .ThreadFactory ;
4749import com .rabbitmq .client .impl .AMQChannel .BlockingRpcContinuation ;
4850import com .rabbitmq .utility .BlockingCell ;
4951
@@ -61,6 +63,9 @@ final class Copyright {
6163public class AMQConnection extends ShutdownNotifierComponent implements Connection , NetworkConnection {
6264 /** Timeout used while waiting for AMQP handshaking to complete (milliseconds) */
6365 public static final int HANDSHAKE_TIMEOUT = 10000 ;
66+ private final ExecutorService executor ;
67+ private Thread mainLoopThread ;
68+ private ThreadFactory threadFactory = new DefaultThreadFactory ();
6469
6570 /**
6671 * Retrieve a copy of the default table of client properties that
@@ -101,7 +106,7 @@ public static final Map<String, Object> defaultClientProperties() {
101106 }
102107 };
103108
104- protected final ConsumerWorkService _workService ;
109+ protected ConsumerWorkService _workService = null ;
105110
106111 /** Frame source/sink */
107112 private final FrameHandler _frameHandler ;
@@ -124,7 +129,7 @@ public static final Map<String, Object> defaultClientProperties() {
124129 private volatile boolean _inConnectionNegotiation ;
125130
126131 /** Manages heart-beat sending for this connection */
127- private final HeartbeatSender _heartbeatSender ;
132+ private HeartbeatSender _heartbeatSender ;
128133
129134 private final String _virtualHost ;
130135 private final Map <String , Object > _clientProperties ;
@@ -210,16 +215,23 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler)
210215 this .requestedChannelMax = params .getRequestedChannelMax ();
211216 this .requestedHeartbeat = params .getRequestedHeartbeat ();
212217 this .saslConfig = params .getSaslConfig ();
218+ this .executor = params .getExecutor ();
213219
214- this ._workService = new ConsumerWorkService (params .getExecutor ());
215220 this ._channelManager = null ;
216221
217- this ._heartbeatSender = new HeartbeatSender (frameHandler );
218222 this ._brokerInitiatedShutdown = false ;
219223
220224 this ._inConnectionNegotiation = true ; // we start out waiting for the first protocol response
221225 }
222226
227+ private void initializeConsumerWorkService () {
228+ this ._workService = new ConsumerWorkService (executor , threadFactory );
229+ }
230+
231+ private void initializeHeartbeatSender () {
232+ this ._heartbeatSender = new HeartbeatSender (_frameHandler , threadFactory );
233+ }
234+
223235 /**
224236 * Start up the connection, including the MainLoop thread.
225237 * Sends the protocol
@@ -239,6 +251,8 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler)
239251 public void start ()
240252 throws IOException
241253 {
254+ initializeConsumerWorkService ();
255+ initializeHeartbeatSender ();
242256 this ._running = true ;
243257 // Make sure that the first thing we do is to send the header,
244258 // which should cause any socket errors to show up for us, rather
@@ -262,7 +276,9 @@ public void start()
262276 }
263277
264278 // start the main loop going
265- new MainLoop ("AMQP Connection " + getHostAddress () + ":" + getPort ()).start ();
279+ MainLoop loop = new MainLoop ();
280+ mainLoopThread = threadFactory .newThread (loop , "AMQP Connection " + getHostAddress () + ":" + getPort ());
281+ mainLoopThread .start ();
266282 // after this point clear-up of MainLoop is triggered by closing the frameHandler.
267283
268284 AMQP .Connection .Start connStart = null ;
@@ -335,7 +351,7 @@ public void start()
335351 int channelMax =
336352 negotiateChannelMax (this .requestedChannelMax ,
337353 connTune .getChannelMax ());
338- _channelManager = instantiateChannelManager (channelMax );
354+ _channelManager = instantiateChannelManager (channelMax , threadFactory );
339355
340356 int frameMax =
341357 negotiatedMaxValue (this .requestedFrameMax ,
@@ -372,8 +388,8 @@ public void start()
372388 return ;
373389 }
374390
375- protected ChannelManager instantiateChannelManager (int channelMax ) {
376- return new ChannelManager (this ._workService , channelMax );
391+ protected ChannelManager instantiateChannelManager (int channelMax , ThreadFactory threadFactory ) {
392+ return new ChannelManager (this ._workService , channelMax , threadFactory );
377393 }
378394
379395 /**
@@ -425,6 +441,23 @@ public void setHeartbeat(int heartbeat) {
425441 }
426442 }
427443
444+ /**
445+ * Makes it possible to override thread factory that is used
446+ * to instantiate connection network I/O loop. Only necessary
447+ * in the environments with restricted
448+ * @param threadFactory
449+ */
450+ public void setThreadFactory (ThreadFactory threadFactory ) {
451+ this .threadFactory = threadFactory ;
452+ }
453+
454+ /**
455+ * @return Thread factory used by this connection.
456+ */
457+ public ThreadFactory getThreadFactory () {
458+ return threadFactory ;
459+ }
460+
428461 public Map <String , Object > getClientProperties () {
429462 return new HashMap <String , Object >(_clientProperties );
430463 }
@@ -483,14 +516,7 @@ private static final int negotiatedMaxValue(int clientValue, int serverValue) {
483516 Math .min (clientValue , serverValue );
484517 }
485518
486- private class MainLoop extends Thread {
487-
488- /**
489- * @param name of thread
490- */
491- MainLoop (String name ) {
492- super (name );
493- }
519+ private class MainLoop implements Runnable {
494520
495521 /**
496522 * Channel reader thread main loop. Reads a frame, and if it is
@@ -634,13 +660,14 @@ public void handleConnectionClose(Command closeCommand) {
634660 _channel0 .quiescingTransmit (new AMQP .Connection .CloseOk .Builder ().build ());
635661 } catch (IOException _) { } // ignore
636662 _brokerInitiatedShutdown = true ;
637- Thread scw = new SocketCloseWait (sse );
638- scw .setName ("AMQP Connection Closing Monitor " +
663+ SocketCloseWait scw = new SocketCloseWait (sse );
664+ Thread waiter = threadFactory .newThread (scw );
665+ waiter .setName ("AMQP Connection Closing Monitor " +
639666 getHostAddress () + ":" + getPort ());
640- scw .start ();
667+ waiter .start ();
641668 }
642669
643- private class SocketCloseWait extends Thread {
670+ private class SocketCloseWait implements Runnable {
644671 private final ShutdownSignalException cause ;
645672
646673 public SocketCloseWait (ShutdownSignalException sse ) {
@@ -787,7 +814,7 @@ public void close(int closeCode,
787814 boolean abort )
788815 throws IOException
789816 {
790- boolean sync = !(Thread .currentThread () instanceof MainLoop );
817+ boolean sync = !(Thread .currentThread () == mainLoopThread );
791818
792819 try {
793820 AMQP .Connection .Close reason =
0 commit comments