1919import java .io .InputStream ;
2020import java .io .InterruptedIOException ;
2121import java .nio .ByteBuffer ;
22+ import java .util .Objects ;
2223import java .util .concurrent .ExecutorService ;
2324import java .util .concurrent .Executors ;
2425import java .util .concurrent .TimeUnit ;
@@ -105,6 +106,8 @@ private static Thread newThread(Runnable r) {
105106
106107 private final ExecutorService executorService ;
107108
109+ private final boolean shutdownExecutorService ;
110+
108111 private final Condition asyncReadComplete = stateChangeLock .newCondition ();
109112
110113 /**
@@ -114,7 +117,7 @@ private static Thread newThread(Runnable r) {
114117 * @param bufferSizeInBytes The buffer size.
115118 */
116119 public ReadAheadInputStream (final InputStream inputStream , final int bufferSizeInBytes ) {
117- this (inputStream , bufferSizeInBytes , newExecutorService ());
120+ this (inputStream , bufferSizeInBytes , newExecutorService (), true );
118121 }
119122
120123 /**
@@ -126,14 +129,28 @@ public ReadAheadInputStream(final InputStream inputStream, final int bufferSizeI
126129 */
127130 public ReadAheadInputStream (final InputStream inputStream , final int bufferSizeInBytes ,
128131 final ExecutorService executorService ) {
132+ this (inputStream , bufferSizeInBytes , executorService , false );
133+ }
134+
135+ /**
136+ * Creates an instance with the specified buffer size and read-ahead threshold
137+ *
138+ * @param inputStream The underlying input stream.
139+ * @param bufferSizeInBytes The buffer size.
140+ * @param executorService An executor service for the read-ahead thread.
141+ * @param shutdownExecutorService Whether or not to shutdown the given ExecutorService on close.
142+ */
143+ public ReadAheadInputStream (final InputStream inputStream , final int bufferSizeInBytes ,
144+ final ExecutorService executorService , final boolean shutdownExecutorService ) {
129145 if (bufferSizeInBytes <= 0 ) {
130146 throw new IllegalArgumentException (
131147 "bufferSizeInBytes should be greater than 0, but the value is " + bufferSizeInBytes );
132148 }
133- this .executorService = executorService ;
149+ this .executorService = Objects .requireNonNull (executorService , "executorService" );
150+ this .underlyingInputStream = Objects .requireNonNull (inputStream , "inputStream" );
151+ this .shutdownExecutorService = shutdownExecutorService ;
134152 this .activeBuffer = ByteBuffer .allocate (bufferSizeInBytes );
135153 this .readAheadBuffer = ByteBuffer .allocate (bufferSizeInBytes );
136- this .underlyingInputStream = inputStream ;
137154 this .activeBuffer .flip ();
138155 this .readAheadBuffer .flip ();
139156 }
@@ -177,16 +194,18 @@ public void close() throws IOException {
177194 stateChangeLock .unlock ();
178195 }
179196
180- try {
181- executorService .shutdownNow ();
182- executorService .awaitTermination (Long .MAX_VALUE , TimeUnit .SECONDS );
183- } catch (final InterruptedException e ) {
184- final InterruptedIOException iio = new InterruptedIOException (e .getMessage ());
185- iio .initCause (e );
186- throw iio ;
187- } finally {
188- if (isSafeToCloseUnderlyingInputStream ) {
189- underlyingInputStream .close ();
197+ if (shutdownExecutorService ) {
198+ try {
199+ executorService .shutdownNow ();
200+ executorService .awaitTermination (Long .MAX_VALUE , TimeUnit .SECONDS );
201+ } catch (final InterruptedException e ) {
202+ final InterruptedIOException iio = new InterruptedIOException (e .getMessage ());
203+ iio .initCause (e );
204+ throw iio ;
205+ } finally {
206+ if (isSafeToCloseUnderlyingInputStream ) {
207+ underlyingInputStream .close ();
208+ }
190209 }
191210 }
192211 }
0 commit comments