Java中的守护线程与用户线程

特点

  • 用户线程(User Thread)

        特点:所有用户线程结束,JVM也就停止了。

  • 守护线程(Daemon Thread)

        特点:JVM的停止与否与守护线程无关。

应用场景

  • 用户线程

        绝大多数应用开发场景都会使用用户线程,平时所说的线程也都指用户线程。

  • 守护线程

        由于守护线程的特点,有些特别是中间件开发可以考虑使用守护线程,比如心跳检测,而JVM中的GC垃圾回收也是守护线程的典型应用。

总结

        也就是说如果做偏中间件的开发,可以考虑你所开发的服务是否应该影响JVM停止,如果不需要则可以使用守护线程,但如涉及到了资源关闭,那依旧需要使用用户线程。因为JVM停止不会考虑守护线程,所以守护线程中哪怕使用了finally也不一定会执行。

@Slf4j
public class DaemonAndUserThread {

  /**
  * 守护线程和用户线程的区别:
   * 用户线程没都停止,虚拟机也不会停止.
   * 用户线程都停止了,虚拟机会直接停止,虚拟机停止与守护线程无关.
   * 守护线程应用场景:例如 GC垃圾回收,心跳检测.
  */
  public static void main(String[] args) throws InterruptedException {
    log.info("{} 主线程开始", Thread.currentThread());

    // 主线程停止钩子函数(回调)
    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
      log.info("{} JVM停止", Thread.currentThread());
    }));

    // 守护线程 循环执行
    AtomicInteger fre = new AtomicInteger(1);
    Thread daemonThread = new Thread(() -> {
      while (true) {
        try {
          log.info("{} 守护线程 开始第{}次调度", Thread.currentThread(), fre);
          Thread.sleep(2000);
        } catch (Exception e) {
          log.info("{} 守护线程 第{}次调度发生异常", Thread.currentThread(), fre);
        } finally {
          log.info("{} 守护线程 第{}次执行finally", Thread.currentThread(), fre);
        }
        fre.getAndIncrement();
      }
    });
    // 声明守护线程
    daemonThread.setDaemon(true);
    daemonThread.start();

    // 用户线程 固定次数执行
    Thread userThread = new Thread(() -> {
      for (int i = 1; i <= 2 ; i++) {
          try {
            log.info("{} 用户线程 开始第{}次调度", Thread.currentThread(), i);
            Thread.sleep(2000);
          } catch (Exception e) {
            log.info("{} 用户线程 第{}次调度发生异常", Thread.currentThread(), i);
          } finally {
            log.info("{} 用户线程 第{}次执行finally", Thread.currentThread(), i);
          }
      }
    });
    userThread.start();

    Thread.sleep(3000);
    log.info("{} 主线程唤醒", Thread.currentThread());
  }

}

打印结果:

21:43:02.570 [main] INFO com.example.base.jdk.DaemonAndUserThread - Thread[main,5,main] 主线程开始
21:43:02.573 [Thread-1] INFO com.example.base.jdk.DaemonAndUserThread - Thread[Thread-1,5,main] 守护线程 开始第1次调度
21:43:02.574 [Thread-2] INFO com.example.base.jdk.DaemonAndUserThread - Thread[Thread-2,5,main] 用户线程 开始第1次调度
21:43:04.577 [Thread-1] INFO com.example.base.jdk.DaemonAndUserThread - Thread[Thread-1,5,main] 守护线程 第1次执行finally
21:43:04.577 [Thread-1] INFO com.example.base.jdk.DaemonAndUserThread - Thread[Thread-1,5,main] 守护线程 开始第2次调度
21:43:04.578 [Thread-2] INFO com.example.base.jdk.DaemonAndUserThread - Thread[Thread-2,5,main] 用户线程 第1次执行finally
21:43:04.578 [Thread-2] INFO com.example.base.jdk.DaemonAndUserThread - Thread[Thread-2,5,main] 用户线程 开始第2次调度
21:43:05.579 [main] INFO com.example.base.jdk.DaemonAndUserThread - Thread[main,5,main] 主线程唤醒
21:43:06.582 [Thread-1] INFO com.example.base.jdk.DaemonAndUserThread - Thread[Thread-1,5,main] 守护线程 第2次执行finally
21:43:06.583 [Thread-1] INFO com.example.base.jdk.DaemonAndUserThread - Thread[Thread-1,5,main] 守护线程 开始第3次调度
21:43:06.582 [Thread-2] INFO com.example.base.jdk.DaemonAndUserThread - Thread[Thread-2,5,main] 用户线程 第2次执行finally
21:43:06.585 [Thread-0] INFO com.example.base.jdk.DaemonAndUserThread - Thread[Thread-0,5,main] JVM停止

        可以看到最终用户线程停止后JVM也就直接停止了,而守护线程也没能执行最后的finally,具体应该使用用户线程还是守护线程,需要根据应用场景灵活选择。

你可能感兴趣的:(Java,java,jvm,开发语言,守护线程)