Почему программа не закрывается? - PullRequest
2 голосов
/ 14 марта 2019

Хорошо, я пытался преобразовать сетевой блокирующий запрос в неблокирующий. Библиотека, которую я использую для сетевого ввода-вывода, предоставляет функции для выполнения асинхронных HTTP-вызовов, но в любом случае, ради экспериментов, я попытался сделать это следующим образом:

import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.mashape.unirest.request.GetRequest;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class TestExecutorService {
    private static final ExecutorService executor = Executors.newSingleThreadExecutor();
    static volatile Thread innerThread;

    public static void asyncGet (String url) {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                innerThread = Thread.currentThread();
                GetRequest request = Unirest.get(url);
                try {
                    HttpResponse <String> response = request.asString();
                    System.out.println(response.getBody());
                    Unirest.shutdown();
                } catch (UnirestException exc) {
                    exc.printStackTrace();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        });
    }
}
public class Main {
    public static void main(String[] args) {
        TestExecutorService.asyncGet("https://stackoverflow.com");
        System.out.println("We're already here!");

        try {
            // Delay so that executor service's thread object could be
            // ...assigned to static variable innerThread
            Thread.sleep(100);
            TestExecutorService.innerThread.join();
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

Я не профессиональный программист и не абсолютный новичок, когда дело доходит до параллелизма, и даже я могу сказать, что этот кусок кода можно улучшить, хотя бы немного (одно из тех ощущений, которые вы испытываете как новичок, когда знаете что то не так, но не уверен что есть). В любом случае, что смущает меня в коде выше, так это то, что программа не завершается. Я не ожидал, что это произойдет. Я прочитал немного о Executors.singleThreadExecutor, и у меня есть идея, что если внутренний поток по какой-то причине умирает, он создает новый поток и безопасно «переносит» состояние во вновь созданный поток. Я понятия не имею, почему программа не завершается, хотя. Может кто-нибудь дать несколько советов?

Обратите внимание, что приведенный здесь код не будет использоваться в производственных средах. Я написал это только для практики.

Ответы [ 2 ]

1 голос
/ 14 марта 2019

Вы смешиваете два шаблона.

Если вы используете executor s, вам не нужно присоединяться.Этот поток был запущен системным потоком, а не вашим основным потоком.Это не ваша дочерняя тема, на самом деле вы не можете join это.Просто запустите и забудьте.

Если вы сами создаете поток, а затем запускаете его, вы должны join его.Тогда дочерняя нить ваша.

0 голосов
/ 14 марта 2019

Ваша проблема здесь в том, что поток в вашей службе исполнителя не является потоком демона.Если вы предоставляете ThreadFactory при создании исполнителя, он должен работать.

Executors.newFixedThreadPool(1, 
  new ThreadFactory() {
    public Thread newThread(Runnable r) {
      Thread t = Executors.defaultThreadFactory.newThread(r);
      t.setDaemon(true);
      return t;
   }
});

Это создаст службу исполнителя с потоками демона.У вас также есть некоторое состояние гонки с вашим «сном».Вместо join используйте CountdownLatch.

...