gpt4 book ai didi

java - 即使主线程执行完成,Java应用程序如何继续运行?

转载 作者:行者123 更新时间:2023-12-03 12:48:29 25 4
gpt4 key购买 nike

当应用程序通过Java中的main方法启动时,它将旋转其他用户线程(而不是守护程序)执行以下任务:

  • 用户线程-01:从数据库
  • 加载缓存
  • 用户线程-02:执行应用程序启动任务,例如运行诊断
  • 用户线程-03:其他任务

  • 由主线程启动的用户线程将在某个时间点完成执行并终止。这将导致主线程最终终止,并且应用程序将停止运行。但是,正如我们看到的那样,一旦启动了许多应用程序,它们就会继续运行,如果进行线程转储,我们可以在最底部看到主线程。这意味着主线程没有终止,这意味着启动的用户线程没有终止。
    如何实现的?我的意思是什么标准的编程结构和逻辑来使线程保持 Activity 状态,而无需通过无限for或while循环运行它们?
    感谢您解决这个问题。每个有用的答复将增加我们的知识。

    最佳答案

    执行者框架
    你说:

    spins other user threads


    希望您不会直接解决 Thread对象。从Java 5开始,出于大多数目的,我们可以使用Executors框架来管理后台线程上的工作。请参见Oracle的 tutorial
    ExecutorService es = Executors. … ;
    es.submit( yourRunnableOrCallableHere ) ; // Optional: Capture the returned `Future` object to track success/failure of your task.

    es.shutdown() ;
    后台线程结束对主线程无效
    你说:

    The user threads started by main thread will complete execution at some point in time and terminate. This will cause the main thread to terminate eventually and the application will stop running.


    不正确。
    主线程在没有更多工作要做时结束。后台线程可以在主线程之前或之后终止。后台线程终止不会导致主线程终止。
    这是一些示例代码来演示此行为。此应用程序执行线程转储,然后在后台运行任务,该任务也执行线程转储。主线程和后台线程都 hibernate 几秒钟。
    package work.basil.example;

    import java.lang.management.ManagementFactory;
    import java.lang.management.ThreadInfo;
    import java.lang.management.ThreadMXBean;
    import java.time.Duration;
    import java.time.Instant;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;

    public class Threading
    {
    public static void main ( String[] args )
    {
    Threading app = new Threading();
    app.demo();
    }

    private void demo ( )
    {
    System.out.println( "---------------| main thread |------------------------------------" );
    System.out.println( "Bonjour. " + Instant.now() );
    System.out.println( Threading.threadDump( true , true ) );

    ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.submit(
    ( ) -> {
    System.out.println( "---------------| background thread |------------------------------------" );
    System.out.println( "DEBUG - Starting background thread. " + Instant.now() );
    System.out.println( "DEBUG - Sleeping background thread. " + Instant.now() );
    try {Thread.sleep( Duration.ofSeconds( 2 ).toMillis() );} catch ( InterruptedException e ) {e.printStackTrace();}
    System.out.println( Threading.threadDump( true , true ) );
    System.out.println( "DEBUG - Ending background thread. " + Instant.now() );
    }
    );

    executorService.shutdown(); // Always be sure to shutdown your executor services.
    try {Thread.sleep( Duration.ofSeconds( 5 ).toMillis() );} catch ( InterruptedException e ) {e.printStackTrace();}
    System.out.println( "---------------| main thread |------------------------------------" );
    System.out.println( Threading.threadDump( true , true ) );
    System.out.println( "DEBUG - Main thread ending. " + Instant.now() );
    }

    // `threadDump` method taken from: https://www.baeldung.com/java-thread-dump
    private static String threadDump ( boolean lockedMonitors , boolean lockedSynchronizers )
    {
    StringBuffer threadDump = new StringBuffer( System.lineSeparator() );
    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
    for ( ThreadInfo threadInfo : threadMXBean.dumpAllThreads( lockedMonitors , lockedSynchronizers ) )
    {
    String message = "Thread: " + threadInfo.getThreadId() + " | " + threadInfo.getThreadName();
    threadDump.append( message ).append( System.lineSeparator() );
    // threadDump.append( threadInfo.toString() );
    }
    return threadDump.toString();
    }
    }
    当我们使后台线程 hibernate 的时间少于主线程的时间(2秒对5秒)时,请注意主线程继续运行。后台线程结束对主线程继续或结束没有影响。
    运行时,请注意,在此处使用已提交的任务启动执行程序服务如何导致另外两个ID为14和15的线程。然后,在后台任务结束并关闭了执行程序服务之后,ID为14的线程消失了。请注意主线程如何结束并继续工作-与您在问题中的陈述相矛盾。
    /Library/Java/JavaVirtualMachines/jdk-16.jdk/Contents/Home/bin/java -javaagent:/Users/basilbourque/Library/Application Support/JetBrains/Toolbox/apps/IDEA-U/ch-0/203.5981.155/IntelliJ IDEA 2020.3 EAP.app/Contents/lib/idea_rt.jar=49389:/Users/basilbourque/Library/Application Support/JetBrains/Toolbox/apps/IDEA-U/ch-0/203.5981.155/IntelliJ IDEA 2020.3 EAP.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/basilbourque/IdeaProjects/Loom/target/classes work.basil.example.Threading
    ---------------| main thread |------------------------------------
    Bonjour. 2020-12-18T07:30:21.107455Z

    Thread: 1 | main
    Thread: 2 | Reference Handler
    Thread: 3 | Finalizer
    Thread: 4 | Signal Dispatcher
    Thread: 11 | Common-Cleaner
    Thread: 12 | Monitor Ctrl-Break
    Thread: 13 | Notification Thread

    ---------------| background thread |------------------------------------
    DEBUG - Starting background thread. 2020-12-18T07:30:21.268025Z
    DEBUG - Sleeping background thread. 2020-12-18T07:30:21.268225Z

    Thread: 1 | main
    Thread: 2 | Reference Handler
    Thread: 3 | Finalizer
    Thread: 4 | Signal Dispatcher
    Thread: 11 | Common-Cleaner
    Thread: 12 | Monitor Ctrl-Break
    Thread: 13 | Notification Thread
    Thread: 14 | pool-1-thread-1
    Thread: 15 | Attach Listener

    DEBUG - Ending background thread. 2020-12-18T07:30:23.275729Z
    ---------------| main thread |------------------------------------

    Thread: 1 | main
    Thread: 2 | Reference Handler
    Thread: 3 | Finalizer
    Thread: 4 | Signal Dispatcher
    Thread: 11 | Common-Cleaner
    Thread: 12 | Monitor Ctrl-Break
    Thread: 13 | Notification Thread
    Thread: 15 | Attach Listener

    DEBUG - Main thread ending. 2020-12-18T07:30:26.271499Z

    Process finished with exit code 0
    有趣的是,请尝试使用该代码,但要反转持续时间。使用5秒和2秒来查看后台线程是否比主线程有效。
    Web服务器一直忙于监听
    您在 a comment中说过:

    visualize it like this ... we have a website which is alive even when no one is opening the web page in the browser ... which means the application is running even when no one is interacting with it ... if we say that it is the web server which is running in background and not the actual web application .... but, then how is the web application is running indefinitely even when no one is interacting with it.


    关于“即使没有人在浏览器中打开网页,我们的网站仍然活跃”,没有一个网站不是“活跃的”。没有任何待处理的HTTP请求,您的Java Servlet不会执行。您的servlet已加载并初始化,但是直到请求到达时才执行。
    关于“这意味着该应用程序即使在没有人与之交互的情况下仍在运行”,如上所述,没有您的Web应用程序未在运行。您的Java Servlet代码未执行。当请求到达时,Web容器会自动在线程中调用Servlet的代码。最终,该servlet代码导致生成内容,并将其作为响应发送回Web浏览器。 Servlet代码的执行结束。用于执行的线程要么结束,要么返回到线程池(由Web容器做出的内部决定)。为了简单起见,我忽略了 Push technologyWebSockets
    关于:“如果我们说是Web服务器在后台运行,而不是实际的Web应用程序”,则该Web服务器始终在运行一个额外的线程来监听传入的请求。
    ➥这可能是造成困惑的根源: Web服务器始终忙,忙于监听传入的连接,无论是否执行Java servlet代码。
  • Web服务器具有一个专用于与主机OS一起使用的线程,以在网络上监听传入的连接。
  • Web服务器根据需要通过制定和发送响应来启动其他线程来响应请求。

  • 关于:“即使没有人与Web应用程序交互,Web应用程序如何无限期运行”,您也忘记了主机OS​​与Web容器交互,无论用户是否与Web应用程序交互。 Web容器维护一个线程以监听传入的连接。该线程处于阻塞状态,等待主机操作系统的网络堆栈通知传入请求。 (我在这里的描述是概括性的,并且是简化的-我不是网络专家-但这足以说明这一点。)
    当通过网络收到请求时,主机OS会通知Web容器。该通知解除阻塞监听线程。监听线程将请求分派(dispatch)到新线程,从而执行Java Servlet的代码。同时,Web容器的请求监听线程返回到阻塞状态,以等待来自主机OS网络堆栈的有关另一个传入请求的另一个通知。
    阻塞的监听线程是解释/启用Web服务器连续且无限期运行的原因。相反,您的Web应用仅在响应请求时突然运行。
    您的问题要归功于Java Servlet技术的天才和成功。 Java Servlet的主要目的是抽象出所有有关监听网络 Activity 的细节,将数据包转换为文本以解密请求,解析该请求,将请求的内容映射为特定servlet的责任,从而确保特定servlet是加载并初始化,并最终在Servlet规范定义的Servlet代码中调用特定方法。
    用户应用一直忙于等待输入
    与Web服务器始终忙于监听传入的请求类似, console appsgui apps都始终忙于监听用户输入。他们有时可能看起来很闲,但事实并非如此。
    尽管用户应用程序无法在CPU上持续旋转,但它们确实维护了与主机OS配合使用的线程,以通知用户事件,例如键盘键入和鼠标移动/点击。

    关于java - 即使主线程执行完成,Java应用程序如何继续运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65346065/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com