先来看个例子:

  • 首先我们知道线程的几个状态,从new Thread 开始为New状态,当调用start()方法后,变为runnable状态,接下来有可能变为:Running | Terminated | Blocked 状态。

  • 以上代码线程状态:

    • new Thread 开始为 New 状态
    • 调用start()方法后为 Runnable 状态。
    • 执行System.out.println(Thread.currentThread().getName()+" running");后为: Running 状态。
    • 执行Thread.sleep(10000);后为:Blocked 状态。
    • 执行完后 Terminated 状态。
  • 以上为Thread t 线程,main线程呢?

    • 执行public static void main(String[] args) 后 Running 状态。
      • 执行Thread.sleep(10_000);后为:Blocked 状态。
    • 执行System.out.println(Thread.currentThread().getName()); 后 Terminated 状态。

问题:两个线程皆结束为什么JVM没有退出呢?

  • 运行结果:

  • main线程这个时候是已经结束了的,从JConsole工具可以看出:

  • application 没有退的原因是因为还有一些active的线程。

  • JVM怎么知道这些active的线程呢?

    • 因为放到了同一个ThreadGroup里面,也是通过ThreadGroup去管理的,它看到了active线程还是有活跃的
  • 加多个属性把thread t 设置为守护线程

      t.setDaemon(true);
    
  • 当main线程生命周期结束之后,创建的守护线程也就跟着结束!

  • 运行结果:

  • 不管thread t 是否Running结束都把线程干掉。

  • 这东西的用处:

    • 建立网络连接
      • A(client)<--------------------------->B(server)
      • 从A到B建立长连接,每隔3秒发送一次心跳包。
      • A不断的向B发送心跳包,B返回心跳相应,证明这个连接是可用的,如果不可用重新连接。
      • 一旦当前的线程创建好了一个线程之后,要维护这个心跳,这个心跳和业务没有关系,和这个连接要拿去发送报文或通信也没有多大关系,就是做维护的一些事情。
      • 这时,在创建连接之后的线程开辟一个daemonThread(health check)做心跳检查。
      • 好处:
        • 假设没有做成daemonThread,当建立连接的这个线程可能已经死了,但是你的哪个线程它不会死,必须你通知他或者手动关掉,关闭时可能还关不了,因为标记为不可用了。
        • 也就是说所有的业务线程都已经死掉了,但是应用程序关不了。(进程一直还在,因为还有活动线程在运行,JVM不会退出,但是又没有做什么事情,可能在通信的过程中不断的报错,但你不知道)。
        • 如果设置为守护线程那就很容易得到解决。(守护线程可以帮你做一些辅助性的东西)。

问题:在Thread里面创建daemonThread t,启动后main线程结束,t随之结束,那么在t里面再创建一个线程L把他设置为daemonThread,t结束后他会退出吗?

问题:如果把L设置为非守护线程,mian和t运行结束之后,JVM能退出吗?

  • 在Thread t 里面创建线程L休眠100秒后做一些事情。
  • t休眠一秒后退出后,L肯定也退出了。

  • 运行结果:

  • t的生命周期结束后,里面的守护线程T线程也跟着退出了,这就好比建立通信时的那个线程。

  • 父线程结束后,子线程也会结束(守护线程)。

  • 如果L为非守护线程,t线程由于某种原因,操作的时候抛出异常结束点了,他创建的子线程L还会结束吗? -

  • 非Daemon的线程并不会跟着父线程结束会一直运行(资源无法释放,因为还有线程在运行)。

  • 官方文档说明:

  • 如果再启动后调用setDaemon()方法就会报异常

results matching ""

    No results matching ""