A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© HM代景康 高级黑马   /  2013-10-8 08:53  /  1681 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

public class Test {

  public static void main(String args) {

  Thread t1 = new MyCommon();

  Thread t2 = new Thread(new MyDaemon());

  t2.setDaemon(true); //设置为守护线程

  t2.start();

  t1.start();

  }

  }

  class MyCommon extends Thread {

  public void run() {

  for (int i = 0; i < 5; i++) {

  System.out.println("线程1第" + i + "次执行!");

  try {

  Thread.sleep(7);

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  }

  }

  }

  [html] class MyDaemon implements Runnable {

  public void run() {

  for (long i = 0; i < 9999999L; i++) {

  System.out.println("后台线程第" + i + "次执行!");

  try {

  Thread.sleep(7);

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  }

  }

  }

  class MyDaemon implements Runnable {

  public void run() {

  for (long i = 0; i < 9999999L; i++) {

  System.out.println("后台线程第" + i + "次执行!");

  try {

  Thread.sleep(7);

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  }

  }

  }

  后台线程第0次执行!

  线程1第0次执行!

  线程1第1次执行!

  后台线程第1次执行!

  后台线程第2次执行!

  线程1第2次执行!

  线程1第3次执行!

  后台线程第3次执行!

  线程1第4次执行!

  后台线程第4次执行!

  后台线程第5次执行!

  后台线程第6次执行!

  后台线程第7次执行!

  Process finished with exit code 0

  从上面的执行结果可以看出:

  前台线程是保证执行完毕的,后台线程还没有执行完毕就退出了。

  实际上:JRE判断程序是否执行结束的标准是所有的前台执线程行完毕了,而不管后台线程的状态,因此,在使用后台县城时候一定要注意这个问题。

  补充说明:

  定义:守护线程--也称“服务线程”,在没有用户线程可服务时会自动离开。

  优先级:守护线程的优先级比较低,用于为系统中的其它对象和线程提供服务。

  设置:通过setDaemon(true)来设置线程为“守护线程”;将一个用户线程设置为

  守护线程的方式是在 线程对象创建 之前 用线程对象的setDaemon方法。

  example: 垃圾回收线程就是一个经典的守护线程,当我们的程序中不再有任何运行的

  Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是

  JVM上仅剩的线程时,垃圾回收线程会自动离开。它始终在低级别的状态中运行,用于

  实时监控和管理系统中的可回收资源。

  生命周期:守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且

  周期性地执行某种任务或等待处理某些发生的事件。也就是

  说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”。那Java的守护线程是

  什么样子的呢。当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个

  或以上的非守护线程则JVM不会退出。

  实际应用例子:

  在使用长连接的comet服务端推送技术中,消息推送线程设置为守护线程,服务于ChatServlet的servlet用户线程,在servlet的init启动消息线程,servlet一旦初始化后,一直存在服务器,servlet摧毁后,消息线程自动退出

  容器收到一个Servlet请求,调度线程从线程池中选出一个工作者线程,将请求传递给该工作者线程,然后由该线程来执行Servlet的 service方法。当这个线程正在执行的时候,容器收到另外一个请求,调度线程同样从线程池中选出另一个工作者线程来服务新的请求,容器并不关心这个请求是否访问的是同一个Servlet.当容器同时收到对同一个Servlet的多个请求的时候,那么这个Servlet的service()方法将在多线程中并发执行。

  Servlet容器默认采用单实例多线程的方式来处理请求,这样减少产生Servlet实例的开销,提升了对请求的响应时间,对于Tomcat可以在server.xml中通过元素设置线程池中线程的数目。

  如图:


  为什么要用守护线程?

  我们知道静态变量是ClassLoader级别的,如果Web应用程序停止,这些静态变量也会从JVM中清除。但是线程则是JVM级别的,如果你在Web 应用中启动一个线程,这个线程的生命周期并不会和Web应用程序保持同步。也就是说,即使你停止了Web应用,这个线程依旧是活跃的。正是因为这个很隐晦 的问题,所以很多有经验的开发者不太赞成在Web应用中私自启动线程。

  如果我们手工使用JDK Timer(Quartz的Scheduler),在Web容器启动时启动Timer,当Web容器关闭时,除非你手工关闭这个Timer,否则Timer中的任务还会继续运行!

  下面通过一个小例子来演示这个“诡异”的现象,我们通过ServletContextListener在Web容器启动时创建一个Timer并周期性地运行一个任务:

  [java] /代码清单StartCycleRunTask:容器监听器

  package com.baobaotao.web;

  import java.util.Date;

  import java.util.Timer;

  import java.util.TimerTask;

  import javax.servlet.ServletContextEvent;

  import javax.servlet.ServletContextListener;

  public class StartCycleRunTask implements ServletContextListener ...{

  private Timer timer;

  public void contextDestroyed(ServletContextEvent arg0) ...{

  // ②该方法在Web容器关闭时执行

  System.out.println("Web应用程序启动关闭...");

  }

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马