22
33import java .net .InetSocketAddress ;
44import java .net .SocketAddress ;
5+ import java .nio .channels .AsynchronousChannelGroup ;
56import java .nio .channels .AsynchronousSocketChannel ;
67import java .nio .channels .CompletionHandler ;
78import java .util .Optional ;
89import java .util .concurrent .CompletableFuture ;
10+ import java .util .concurrent .ExecutorService ;
911import java .util .concurrent .Executors ;
1012import java .util .concurrent .ScheduledExecutorService ;
1113import java .util .concurrent .atomic .AtomicBoolean ;
@@ -43,6 +45,8 @@ public class DefaultClientNetwork<C extends Connection<C>> extends AbstractNetwo
4345
4446 @ Getter
4547 final ScheduledExecutorService scheduledExecutor ;
48+ final ExecutorService networkExecutor ;
49+ final AsynchronousChannelGroup channelGroup ;
4650
4751 @ Nullable
4852 @ Getter (AccessLevel .PROTECTED )
@@ -57,11 +61,17 @@ public DefaultClientNetwork(
5761 BiFunction <Network <C >, AsynchronousSocketChannel , C > channelToConnection ) {
5862 super (config , channelToConnection );
5963 this .connecting = new AtomicBoolean (false );
60- this .scheduledExecutor = Executors
61- .newSingleThreadScheduledExecutor (new GroupThreadFactory (config .scheduledThreadGroupName ()));
64+ this .scheduledExecutor = buildScheduledExecutor (config );
65+ this .networkExecutor = buildExecutor (config );
66+ this .channelGroup = Utils .uncheckedGet (networkExecutor , AsynchronousChannelGroup ::withThreadPool );
6267 log .info (config , DefaultClientNetwork ::buildConfigDescription );
6368 }
6469
70+ @ Override
71+ public void inNetworkThread (Runnable task ) {
72+ networkExecutor .execute (task );
73+ }
74+
6575 @ Override
6676 public C connect (InetSocketAddress serverAddress ) {
6777 return connectAsync (serverAddress ).join ();
@@ -88,7 +98,7 @@ public CompletableFuture<C> connectAsync(InetSocketAddress serverAddress) {
8898 var asyncResult = new CompletableFuture <C >();
8999
90100 @ SuppressWarnings ("resource" )
91- var channel = Utils .uncheckedGet (AsynchronousSocketChannel ::open );
101+ var channel = Utils .uncheckedGet (channelGroup , AsynchronousSocketChannel ::open );
92102 channel .connect (serverAddress , this , new CompletionHandler <>() {
93103 @ Override
94104 public void completed (@ Nullable Void result , DefaultClientNetwork <C > network ) {
@@ -136,6 +146,33 @@ public void shutdown() {
136146 if (connection != null ) {
137147 Utils .unchecked (connection , C ::close );
138148 }
149+ channelGroup .shutdown ();
150+ scheduledExecutor .shutdown ();
151+ networkExecutor .shutdown ();
152+ }
153+
154+ protected ExecutorService buildExecutor (NetworkConfig config ) {
155+ var threadFactory = new GroupThreadFactory (
156+ config .threadGroupName (),
157+ config .threadConstructor (),
158+ config .threadPriority (),
159+ false );
160+ ExecutorService executorService = Executors .newSingleThreadScheduledExecutor (threadFactory );
161+ // activate the executor
162+ executorService .submit (() -> {});
163+ return executorService ;
164+ }
165+
166+ protected ScheduledExecutorService buildScheduledExecutor (NetworkConfig config ) {
167+ var threadFactory = new GroupThreadFactory (
168+ config .scheduledThreadGroupName (),
169+ config .threadConstructor (),
170+ config .threadPriority (),
171+ false );
172+ ScheduledExecutorService scheduledExecutor = Executors .newSingleThreadScheduledExecutor (threadFactory );
173+ // activate the executor
174+ scheduledExecutor .submit (() -> {});
175+ return scheduledExecutor ;
139176 }
140177
141178 private static String buildConfigDescription (NetworkConfig conf ) {
0 commit comments