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 ;
4546import com .rabbitmq .client .SaslConfig ;
4647import com .rabbitmq .client .SaslMechanism ;
4748import com .rabbitmq .client .ShutdownSignalException ;
49+ import com .rabbitmq .client .ThreadFactory ;
4850import com .rabbitmq .client .impl .AMQChannel .BlockingRpcContinuation ;
4951import com .rabbitmq .utility .BlockingCell ;
5052
@@ -62,6 +64,9 @@ final class Copyright {
6264public class AMQConnection extends ShutdownNotifierComponent implements Connection , NetworkConnection {
6365 /** Timeout used while waiting for AMQP handshaking to complete (milliseconds) */
6466 public static final int HANDSHAKE_TIMEOUT = 10000 ;
67+ private final ExecutorService executor ;
68+ private Thread mainLoopThread ;
69+ private ThreadFactory threadFactory = new DefaultThreadFactory ();
6570
6671 /**
6772 * Retrieve a copy of the default table of client properties that
@@ -102,7 +107,7 @@ public static final Map<String, Object> defaultClientProperties() {
102107 }
103108 };
104109
105- protected final ConsumerWorkService _workService ;
110+ protected ConsumerWorkService _workService = null ;
106111
107112 /** Frame source/sink */
108113 private final FrameHandler _frameHandler ;
@@ -125,7 +130,7 @@ public static final Map<String, Object> defaultClientProperties() {
125130 private volatile boolean _inConnectionNegotiation ;
126131
127132 /** Manages heart-beat sending for this connection */
128- private final HeartbeatSender _heartbeatSender ;
133+ private HeartbeatSender _heartbeatSender ;
129134
130135 private final String _virtualHost ;
131136 private final Map <String , Object > _clientProperties ;
@@ -212,17 +217,25 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler)
212217 this .requestedChannelMax = params .getRequestedChannelMax ();
213218 this .requestedHeartbeat = params .getRequestedHeartbeat ();
214219 this .saslConfig = params .getSaslConfig ();
220+ this .executor = params .getExecutor ();
221+ this .threadFactory = params .getThreadFactory ();
215222
216- this ._workService = new ConsumerWorkService (params .getExecutor ());
217223 this ._channelManager = null ;
218224
219- this ._heartbeatSender = new HeartbeatSender (frameHandler );
220225 this ._brokerInitiatedShutdown = false ;
221226
222227 this ._inConnectionNegotiation = true ; // we start out waiting for the first protocol response
223228 }
224229
225- /**
230+ private void initializeConsumerWorkService () {
231+ this ._workService = new ConsumerWorkService (executor , threadFactory );
232+ }
233+
234+ private void initializeHeartbeatSender () {
235+ this ._heartbeatSender = new HeartbeatSender (_frameHandler , threadFactory );
236+ }
237+
238+ /**
226239 * Start up the connection, including the MainLoop thread.
227240 * Sends the protocol
228241 * version negotiation header, and runs through
@@ -241,6 +254,8 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler)
241254 public void start ()
242255 throws IOException
243256 {
257+ initializeConsumerWorkService ();
258+ initializeHeartbeatSender ();
244259 this ._running = true ;
245260 // Make sure that the first thing we do is to send the header,
246261 // which should cause any socket errors to show up for us, rather
@@ -264,7 +279,9 @@ public void start()
264279 }
265280
266281 // start the main loop going
267- new MainLoop ("AMQP Connection " + getHostAddress () + ":" + getPort ()).start ();
282+ MainLoop loop = new MainLoop ();
283+ mainLoopThread = threadFactory .newThread (loop , "AMQP Connection " + getHostAddress () + ":" + getPort ());
284+ mainLoopThread .start ();
268285 // after this point clear-up of MainLoop is triggered by closing the frameHandler.
269286
270287 AMQP .Connection .Start connStart = null ;
@@ -337,7 +354,7 @@ public void start()
337354 int channelMax =
338355 negotiateChannelMax (this .requestedChannelMax ,
339356 connTune .getChannelMax ());
340- _channelManager = instantiateChannelManager (channelMax );
357+ _channelManager = instantiateChannelManager (channelMax , threadFactory );
341358
342359 int frameMax =
343360 negotiatedMaxValue (this .requestedFrameMax ,
@@ -374,8 +391,8 @@ public void start()
374391 return ;
375392 }
376393
377- protected ChannelManager instantiateChannelManager (int channelMax ) {
378- return new ChannelManager (this ._workService , channelMax );
394+ protected ChannelManager instantiateChannelManager (int channelMax , ThreadFactory threadFactory ) {
395+ return new ChannelManager (this ._workService , channelMax , threadFactory );
379396 }
380397
381398 /**
@@ -427,6 +444,23 @@ public void setHeartbeat(int heartbeat) {
427444 }
428445 }
429446
447+ /**
448+ * Makes it possible to override thread factory that is used
449+ * to instantiate connection network I/O loop. Only necessary
450+ * in the environments with restricted
451+ * @param threadFactory
452+ */
453+ public void setThreadFactory (ThreadFactory threadFactory ) {
454+ this .threadFactory = threadFactory ;
455+ }
456+
457+ /**
458+ * @return Thread factory used by this connection.
459+ */
460+ public ThreadFactory getThreadFactory () {
461+ return threadFactory ;
462+ }
463+
430464 public Map <String , Object > getClientProperties () {
431465 return new HashMap <String , Object >(_clientProperties );
432466 }
@@ -485,14 +519,7 @@ private static final int negotiatedMaxValue(int clientValue, int serverValue) {
485519 Math .min (clientValue , serverValue );
486520 }
487521
488- private class MainLoop extends Thread {
489-
490- /**
491- * @param name of thread
492- */
493- MainLoop (String name ) {
494- super (name );
495- }
522+ private class MainLoop implements Runnable {
496523
497524 /**
498525 * Channel reader thread main loop. Reads a frame, and if it is
@@ -636,13 +663,14 @@ public void handleConnectionClose(Command closeCommand) {
636663 _channel0 .quiescingTransmit (new AMQP .Connection .CloseOk .Builder ().build ());
637664 } catch (IOException _) { } // ignore
638665 _brokerInitiatedShutdown = true ;
639- Thread scw = new SocketCloseWait (sse );
640- scw .setName ("AMQP Connection Closing Monitor " +
666+ SocketCloseWait scw = new SocketCloseWait (sse );
667+ Thread waiter = threadFactory .newThread (scw );
668+ waiter .setName ("AMQP Connection Closing Monitor " +
641669 getHostAddress () + ":" + getPort ());
642- scw .start ();
670+ waiter .start ();
643671 }
644672
645- private class SocketCloseWait extends Thread {
673+ private class SocketCloseWait implements Runnable {
646674 private final ShutdownSignalException cause ;
647675
648676 public SocketCloseWait (ShutdownSignalException sse ) {
@@ -789,7 +817,7 @@ public void close(int closeCode,
789817 boolean abort )
790818 throws IOException
791819 {
792- boolean sync = !(Thread .currentThread () instanceof MainLoop );
820+ boolean sync = !(Thread .currentThread () == mainLoopThread );
793821
794822 try {
795823 AMQP .Connection .Close reason =
0 commit comments