Java 关闭阶段/窗口时终止所有子线程

Java 关闭阶段/窗口时终止所有子线程,java,multithreading,javafx,Java,Multithreading,Javafx,我有多个子线程实例,这些子线程已启动,并应继续在中执行,直到应用程序退出 我有扩展任务的类,我创建线程作为 new Thread(object of the class).start(); 所有线程都应在主阶段关闭时终止 primaryStage.onCloseOperation(){...} 您应该考虑使用ThreadGroup对所有线程进行分组,然后控制它们的行为。Java5在Java.lang.management中添加了ThreadInfo和ThreadMXBean类以获取状态信息

我有多个子线程实例,这些子线程已启动,并应继续在中执行,直到应用程序退出

我有扩展任务的类,我创建线程作为

new Thread(object of the class).start();
所有线程都应在主阶段关闭时终止

primaryStage.onCloseOperation(){...}

您应该考虑使用
ThreadGroup
对所有线程进行分组,然后控制它们的行为。Java5在Java.lang.management中添加了ThreadInfo和ThreadMXBean类以获取状态信息

以下是使用此处提供的教程实现此目的的示例:

获取所有线程的列表

ThreadGroup上的另一个enumerate()方法列出该组的线程。如果第二个参数为true,它将递归地遍历组,用线程对象填充给定数组。从根线程组开始,您将获得JVM中所有线程的列表

这里的问题与列出线程组的问题相同。如果传递给enumerate()的数组太小,可能会从返回的数组中悄悄删除一些线程。因此,您需要猜测数组大小,调用enumerate(),检查返回值,如果数组已满,请重试。要获得一个好的开始猜测,请查看java.lang.management包。那里的ManagementFactory类返回一个ThreadMXBean,其getThreadCount()方法返回JVM中的线程总数。当然,这可能会在稍后改变,但这是一个很好的初步猜测

Thread[] getAllThreads( ) {
    final ThreadGroup root = getRootThreadGroup( );
    final ThreadMXBean thbean = ManagementFactory.getThreadMXBean( );
    int nAlloc = thbean.getThreadCount( );
    int n = 0;
    Thread[] threads;
    do {
        nAlloc *= 2;
        threads = new Thread[ nAlloc ];
        n = root.enumerate( threads, true );
    } while ( n == nAlloc );
    return java.util.Arrays.copyOf( threads, n );
}

您应该考虑使用
ThreadGroup
对所有线程进行分组,然后控制它们的行为。Java5在Java.lang.management中添加了ThreadInfo和ThreadMXBean类以获取状态信息

以下是使用此处提供的教程实现此目的的示例:

获取所有线程的列表

ThreadGroup上的另一个enumerate()方法列出该组的线程。如果第二个参数为true,它将递归地遍历组,用线程对象填充给定数组。从根线程组开始,您将获得JVM中所有线程的列表

这里的问题与列出线程组的问题相同。如果传递给enumerate()的数组太小,可能会从返回的数组中悄悄删除一些线程。因此,您需要猜测数组大小,调用enumerate(),检查返回值,如果数组已满,请重试。要获得一个好的开始猜测,请查看java.lang.management包。那里的ManagementFactory类返回一个ThreadMXBean,其getThreadCount()方法返回JVM中的线程总数。当然,这可能会在稍后改变,但这是一个很好的初步猜测

Thread[] getAllThreads( ) {
    final ThreadGroup root = getRootThreadGroup( );
    final ThreadMXBean thbean = ManagementFactory.getThreadMXBean( );
    int nAlloc = thbean.getThreadCount( );
    int n = 0;
    Thread[] threads;
    do {
        nAlloc *= 2;
        threads = new Thread[ nAlloc ];
        n = root.enumerate( threads, true );
    } while ( n == nAlloc );
    return java.util.Arrays.copyOf( threads, n );
}

我会从一开始就明确地管理你的线程。特别是,在父类中有一个线程池,如下所示:

ExecutionService exec = Executors.newCachedExecutionService();
for(task : tasks){
    exec.execute(task);
}
然后,如果您的任务要保持运行(而不是定期安排),请将您的任务编码为响应中断,如下所示:

while(!Thread.currentThread().isInterrupted()){
    do stuff;
}
这将使任务一直运行到中断。在这种情况下,切勿忽略
InterruptedException
,因为
InterruptedException
在抛出时将
isInterrupted
设置为false,这一点很重要。当您看到
中断异常时执行此操作:

}catch(InterruptedException e){
    Thread.currentThread().interrupt();
    return;
}
然后,您可以启动子任务,如下所示:

ExecutionService exec = Executors.newCachedExecutionService();
for(task : tasks){
    exec.execute(task);
}
现在,当父任务完成时,您只需调用:

exec.shutdownNow();

停止您的子任务。如果您的子任务使用
Thread.currentThread().isInterrupted()
,则必须使用
shutdownNow()
shutdown()
仅在您希望等待任务自行停止时有效)

我会从一开始就明确地管理您的线程。特别是,在父类中有一个线程池,如下所示:

ExecutionService exec = Executors.newCachedExecutionService();
for(task : tasks){
    exec.execute(task);
}
然后,如果您的任务要保持运行(而不是定期安排),请将您的任务编码为响应中断,如下所示:

while(!Thread.currentThread().isInterrupted()){
    do stuff;
}
这将使任务一直运行到中断。在这种情况下,切勿忽略
InterruptedException
,因为
InterruptedException
在抛出时将
isInterrupted
设置为false,这一点很重要。当您看到
中断异常时执行此操作:

}catch(InterruptedException e){
    Thread.currentThread().interrupt();
    return;
}
然后,您可以启动子任务,如下所示:

ExecutionService exec = Executors.newCachedExecutionService();
for(task : tasks){
    exec.execute(task);
}
现在,当父任务完成时,您只需调用:

exec.shutdownNow();

停止您的子任务。如果您的子任务使用
Thread.currentThread().isInterrupted()
,则必须使用
shutdownNow()
shutdown()
仅在您希望等待任务自行停止时有效)

创建一个
ExecutorService
,它有一个
ThreadFactory
来创建守护进程线程

例如:

ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() {
     @Override
     public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        return thread;
     }
});
剩下的怎么用,@Enno已经说过了


谢谢Enno:)

创建一个
ExecutorService
,它有一个
ThreadFactory
来创建守护进程线程

例如:

ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() {
     @Override
     public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        return thread;
     }
});
剩下的怎么用,@Enno已经说过了


谢谢Enno:)

如何使用ExecutorService创建新线程?或者任何自动创建的线程都属于ExecutorService?@ItachiUchiha:啊,对不起,忘了提到如何启动任务。现在编辑它。线程将由executor服务管理,是的。实际上我在不同的类中启动了新线程,我是否应该将“exec”的引用传递给类的构造函数?或者这又是一个糟糕的设计?@ItachiUchiha:那很好。我如何使用ExecutorService创建新线程?或者任何自动创建的线程都属于ExecutorService?@ItachiUchiha:啊,对不起,忘了提到如何启动任务。现在编辑它。线程将由executor服务管理,是的。实际上我在不同的类中启动了新线程,我是否应该将“exec”的引用传递给类的构造函数?否则这又是一个糟糕的设计