为什么程序不退出?
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
它。那么子线程就是你的了
好的,所以我试图将阻塞网络请求转换为非阻塞请求。我用于网络 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
它。那么子线程就是你的了