为什么程序不退出?

Why won't the program exit?

好的,所以我试图将阻塞网络请求转换为非阻塞请求。我用于网络 I/O 的库确实提供了进行异步 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://whosebug.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 的内容,我有一个想法,如果内部线程由于某种原因死亡,它会创建一个新线程并将 "transports" 状态安全地传递给新创建的线程。我不知道为什么程序没有终止。有人可以给一些提示吗?

请注意,此处提供的代码不会用于生产环境。我写这个只是为了练习。

你的问题是执行者服务中的线程不是守护线程。如果您在创建执行程序时提供 ThreadFactory,那么它应该可以工作。

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

这将生成一个带有守护线程的执行程序服务。 您的 'sleep' 也有一些竞争条件。 使用 CountdownLatch.

而不是 join

您正在混合两种模式。

如果您正在使用 executor,则无需加入。该线程是由系统线程启动的,而不是您的主线程。这不是您的子线程,实际上您 不能 join 它。开火就忘了。

如果你自己创建线程,那么运行它,你应该join它。那么子线程就是你的了