Служба исполнителя остановит поток, ожидающий ввода-вывода - PullRequest
1 голос
/ 12 апреля 2020

Я использую Apache общую библиотеку для загрузки страницы из Интернета. Вот упрощенная версия программы

 public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newSingleThreadExecutor(r -> new Thread(r,"second"));
        final ExecutorService service = Executors.newFixedThreadPool(2, r -> new Thread(r,"first"));
        final Future<Object> submit = executorService.submit(() -> {
            final Future<Object> create = service.submit(() -> {
                System.out.println("Start");
                org.apache.commons.io.IOUtils.copy(new URL("ny_url").openStream(), new FileWriter(new File("create")));
                System.out.println("End");
                return null;
            });
            try {
                return create.get();
            } catch (InterruptedException exc) {
                System.out.println("Interrupted");
                create.cancel(true);
                return null;
            }
        });
        try {
            submit.get(3000, TimeUnit.MILLISECONDS);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } catch (TimeoutException e) {
            System.out.println("Timeout");
            submit.cancel(true);
            System.out.println("HERE2");
        }
        executorService.shutdown();
        service.shutdownNow();
    }

Как вы можете видеть, у меня есть два исполнителя: первый загружает веб-страницу и второй один ожидает завершения три секунды, если задание не смогло загрузить страницу за 3 секунды, тогда основной поток отправляет прерывание, мой второй исполнитель перехватывает это исключение и вызывает future.cancel(true);, наконец, я выключаю обоих исполнителей, однако первый исполнитель все еще работает это дамп потока для него

first" #11 prio=5 os_prio=0 tid=0x00007f18b0002000 nid=0x527d runnable [0x00007f18de08a000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:171)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
    at sun.security.ssl.InputRecord.read(InputRecord.java:503)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975)
    - locked <0x00000000d9004a60> (a java.lang.Object)
    at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:933)
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
    - locked <0x00000000d9004b20> (a sun.security.ssl.AppInputStream)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:284)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
    - locked <0x00000000d9006b60> (a java.io.BufferedInputStream)
    at sun.net.www.MeteredStream.read(MeteredStream.java:134)
    - locked <0x00000000d9006b88> (a sun.net.www.http.KeepAliveStream)
    at java.io.FilterInputStream.read(FilterInputStream.java:133)
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3444)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    - locked <0x00000000d902a040> (a java.io.InputStreamReader)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.Reader.read(Reader.java:140)
    at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2001)
    at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1980)
    at org.apache.commons.io.IOUtils.copy(IOUtils.java:1957)
    at org.apache.commons.io.IOUtils.copy(IOUtils.java:1907)
    at org.apache.commons.io.IOUtils.copy(IOUtils.java:1886)
    at com.devadmin.nma.downloader.TestExecutor.lambda$null$2(TestExecutor.java:17)

Так что я предполагаю, что работа первого исполнителя ничего не знает о прерывании, потому что он ожидает ввода-вывода, вопрос в том, Apache commons не проверяет Thread.isInterrupted при копировании потока можно ли остановить этот поток без изменения библиотеки, спасибо

1 Ответ

0 голосов
/ 12 апреля 2020

Я прочитал этот блог https://techblog.bozho.net/interrupting-executor-tasks/, который дал мне представление о том, как это сделать. Вот как выглядит моя программа сейчас

ExecutorService executorService = Executors.newSingleThreadExecutor(r -> new Thread(r, "second"));
        final ExecutorService service = Executors.newFixedThreadPool(2, r -> new Thread(r, "first"));
        final InputStream inputStream = new URL("https://ep.t8cdn.com/201804/17/47295201/mp4_ultra_47295201.mp4?validfrom=1586656571&validto=1586663771&rate=94k&burst=1600k&ip=66.183.216.58&hash=FXdFmkw14K1PuL9lc8GzOjzcaeI%3D").openStream();
        final Future<Object> submit = executorService.submit(() -> {
            final Future<Object> create = service.submit(() -> {
                System.out.println("Start");
                IOUtils.copy(inputStream, new FileWriter(new File("create")));
                System.out.println("End");
                return null;
            });
            try {
                return create.get();
            } catch (InterruptedException exc) {
                System.out.println("Interrupted");
                create.cancel(true);
                inputStream.close();
                return null;
            }
        });
        try {
            submit.get(3000, TimeUnit.MILLISECONDS);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } catch (TimeoutException e) {
            System.out.println("Timeout");
            submit.cancel(true);
            System.out.println("HERE2");
        }
        executorService.shutdownNow();
        service.shutdownNow();

Я создал поток перед отправкой это первому исполнителю, и я закрыл во втором исполнителе

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...