简体   繁体   中英

Why won't the program exit?

Okay, so I was trying to convert a blocking network request to a non-blocking request. The library that I'm using for network I/O does provide functions to make asynchronous HTTP calls, but anyways, for the sake of experiments, I tried to do it this way:

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();
        }
    }
}

I'm not a pro programmer and an absolute beginner when it comes to concurrency, and even I could tell that this piece of code can be improved, at least bit (one of those feelings you have as a beginner when you know something is wrong, but not sure what is). Anyways, what confuses me about the code above is that the program does not terminate. I didn't expect that to happen. I read a bit about Executors.singleThreadExecutor and I have an idea that if the inner thread dies for some reason, it creates a new thread and "transports" the state safely to the newly created thread. I've no clue why the program does not terminate though. Can someone give some hints?

Please note that the code provided here will not be used in production environments. I wrote this just for practice.

You are mixing two patterns.

If you are using executor s, you don't need to join. That thread was started by a system thread, not your main thread. It is not your child thread, actually you cannot join it. Just fire and forget.

If you create the thread yourself, then run it, you should join it. Then the child thread is yours.

Your problem here is that the thread in your executor service is not a daemon thread. If you supply a ThreadFactory when you create your executor, then it should work.

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

This will produce a executor service with daemon threads. You also have a bit of a race condition with your 'sleep'. Instead of join , use a CountdownLatch .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM