Java ExecutorService-为什么这个程序一直在运行?

Java ExecutorService-为什么这个程序一直在运行?,java,multithreading,executorservice,Java,Multithreading,Executorservice,我正在尝试构建一个类似于后台任务执行器的东西,如果没有应答,它会在一段时间后终止后台任务(后台任务调用Web服务,它们可以超时,但我需要确保它们在一段时间内超时) 所以我把它作为一个实验,但如果我运行它,程序不会终止。我想知道这是否是因为一个后台线程仍然处于活动状态?我怎样才能关掉这个 public class Test { public static class Task implements Callable<Object> { @Override publi

我正在尝试构建一个类似于后台任务执行器的东西,如果没有应答,它会在一段时间后终止后台任务(后台任务调用Web服务,它们可以超时,但我需要确保它们在一段时间内超时)

所以我把它作为一个实验,但如果我运行它,程序不会终止。我想知道这是否是因为一个后台线程仍然处于活动状态?我怎样才能关掉这个

public class Test {

public static class Task implements Callable<Object> {

    @Override
    public Object call() throws Exception {
        while(true) {}
    }

}

public static void main(String[] args) {
    try {
        Task t = new Task();
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.invokeAll(Arrays.asList(t), 5L, TimeUnit.SECONDS);
        executor.shutdown();
        System.out.println("DONE");
    } 
    catch (InterruptedException e) {
        e.printStackTrace();
    }
}
公共类测试{
公共静态类任务实现了可调用{
@凌驾
公共对象调用()引发异常{
while(true){}
}
}
公共静态void main(字符串[]args){
试一试{
任务t=新任务();
ExecutorService executor=Executors.newSingleThreadExecutor();
executor.invokeAll(Arrays.asList(t),5L,TimeUnit.SECONDS);
executor.shutdown();
系统输出打印项次(“完成”);
} 
捕捉(中断异常e){
e、 printStackTrace();
}
}

}ExecutorService不会杀死正在运行的线程,而且由于线程是作为非守护进程创建的,所以JVM不会退出

发生的情况是,当超时过期时,invokeAll()返回的未来将被取消,这意味着在future对象上设置了一个标志,如果您尝试调用
future.get()
,您将得到一个
CancellationException
。但是,invokeAll()和shutdownNow()都不能终止线程

请注意,您甚至不能自己杀死线程。您所能做的就是设置一些特定于应用程序的标志或调用
Thread.interrupt()
,但即使这样也不能保证这一点。

有一篇关于执行器如何工作的文章。这是他的教程摘录

因此,基本上执行器总是在侦听新任务或可调用/可运行的任务,而关闭执行器或阻止执行器侦听的一种方法是中断它正在执行的任何任务。一种方法是调用future.get(),它在主线程停止时停止,挂起它,并确保当前线程在将资源移交给其他线程之前完全执行

您可能有更多的线程,并在InterruptedException块中编写代码以正常关闭

以下是我编写和测试的示例代码:

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ExecutorTest {

    public static void main(String[] args) {

        ExecutorService service = Executors.newWorkStealingPool(10);

        Callable<AccountClass> newInstance = () -> {
            TimeUnit.SECONDS.sleep(3);
            return getAcc(Thread.currentThread().getId());
        };

        // for now only one instance is added to the list
        // List<Callable<AccountClass>> callablesSingleList = Arrays.asList(newInstance);

        // adding multipleCallalbes
        List<Callable<AccountClass>> callablesMultipleList = Arrays.asList(
                () -> {
                    TimeUnit.SECONDS.sleep(3);
                    return getAcc(Thread.currentThread().getId());
                },
                () -> {
                    TimeUnit.SECONDS.sleep(3);
                    return getAcc(Thread.currentThread().getId());
                },
                () -> {
                    TimeUnit.SECONDS.sleep(3);
                    return getAcc(Thread.currentThread().getId());
                });

        try {
            service.invokeAll(callablesMultipleList).stream().map(future -> {
                AccountClass fuClass = null;
                try {
                    fuClass = future.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
                return fuClass;
            }).forEach(getValue -> {
                System.out.println("retunred value:" + getValue);
            });
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }

    }

    private static AccountClass getAcc(long itr) {
        // probably call DB for every new thread iterator
        System.out.println("getting the current thread" + itr);
        AccountClass ac = new AccountClass();
        ac.setId(itr);
        ac.setName("vv");
        ac.setRole("admin");
        System.out.println("sending the accnt class:" + ac);
        return ac;
    }
}
导入java.util.array;
导入java.util.List;
导入java.util.concurrent.Callable;
导入java.util.concurrent.ExecutionException;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.TimeUnit;
公共类测试{
公共静态void main(字符串[]args){
ExecutorService=Executors.newWorkStealingPool(10);
可调用的newInstance=()->{
时间单位。秒。睡眠(3);
返回getAcc(Thread.currentThread().getId());
};
//目前,列表中只添加了一个实例
//List callablesSingleList=Arrays.asList(newInstance);
//添加多个集合
List callablesMultipleList=Arrays.asList(
() -> {
时间单位。秒。睡眠(3);
返回getAcc(Thread.currentThread().getId());
},
() -> {
时间单位。秒。睡眠(3);
返回getAcc(Thread.currentThread().getId());
},
() -> {
时间单位。秒。睡眠(3);
返回getAcc(Thread.currentThread().getId());
});
试一试{
service.invokeAll(callablesMultipleList).stream().map(未来->{
AccountClass fuClass=null;
试一试{
fuClass=future.get();
}捕捉(中断异常e){
e、 printStackTrace();
}捕获(执行例外){
e、 printStackTrace();
}
返回类;
}).forEach(getValue->{
System.out.println(“返回值:+getValue”);
});
}捕获(中断异常例外){
例如printStackTrace();
}
}
私有静态AccountClass getAcc(长itr){
//可能为每个新线程迭代器调用DB
System.out.println(“获取当前线程”+itr);
AccountClass ac=新的AccountClass();
ac.setId(itr);
ac.setName(“vv”);
ac.setRole(“管理员”);
System.out.println(“发送账户类:“+ac”);
返回ac;
}
}
更新:

关闭executor的另一种方法是使用service.shutDownNow()->它关闭程序,即使程序正在执行中。您可以使用waittermination方法指定是否需要几分钟来完成执行,然后可能会关闭服务

import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ExecutorScheduleFixedRate {

    public static void main(String[] args) {

        ScheduledExecutorService service = Executors.newScheduledThreadPool(10);

        Runnable task = () -> {
            getAcc(33);
        };

        service.scheduleWithFixedDelay(task, 10, 5, TimeUnit.SECONDS);

        if (!service.isShutdown()) {
            List<Runnable> list2 = service.shutdownNow();
            System.out.println(list2);
            System.out.println("is shutdonw" + service.isShutdown());
            System.out.println("Do something after the thread execution");
        }

    }

    private static AccountClass getAcc(long itr) {
        // probably call DB for every new thread iterator
        System.out.println("getting the current thread" + itr);
        AccountClass ac = new AccountClass();
        ac.setId(itr);
        ac.setName("vv");
        ac.setRole("admin");
        System.out.println("sending the accnt class:" + ac);
        return ac;
    }

}
import java.util.List;
导入java.util.concurrent.Executors;
导入java.util.concurrent.ScheduledExecutorService;
导入java.util.concurrent.TimeUnit;
公共类ExecutorScheduleFixedRate{
公共静态void main(字符串[]args){
ScheduledExecutorService=Executors.newScheduledThreadPool(10);
可运行任务=()->{
getAcc(33);
};
带有固定延迟的服务调度(任务,10,5,时间单位:秒);
如果(!service.isShutdown()){
List list2=service.shutdownNow();
System.out.println(列表2);
System.out.println(“is shutdonw”+service.isshutton());
System.out.println(“在线程执行之后做一些事情”);
}
}
私有静态AccountClass getAcc(长itr){
//可能为每个新线程迭代器调用DB
System.out.println(“获取当前线程”+itr);
AccountClass ac=新的AccountClass();