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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

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

 在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)

  用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆:

  只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。

  Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。

  User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。

  值得一提的是,守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程。下面的方法就是用来设置守护线程的。

  [java] Thread daemonTread = new Thread();

  // 设定 daemonThread 为 守护线程,default false(非守护线程)

  daemonThread.setDaemon(true);

  // 验证当前线程是否为守护线程,返回 true 则为守护线程

  daemonThread.isDaemon();

  Thread daemonTread = new Thread();

  // 设定 daemonThread 为 守护线程,default false(非守护线程)

  daemonThread.setDaemon(true);

  // 验证当前线程是否为守护线程,返回 true 则为守护线程

  daemonThread.isDaemon();

  这里有几点需要注意:

  (1) thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。

  (2) 在Daemon线程中产生的新线程也是Daemon的。

  (3) 不要认为所有的应用都可以分配给Daemon来进行服务,比如读写操作或者计算逻辑。

  因为你不可能知道在所有的User完成之前,Daemon是否已经完成了预期的服务任务。一旦User退出了,可能大量数据还没有来得及读入或写出,计算任务也可能多次运行结果不一样。这对程序是毁灭性的。造成这个结果理由已经说过了:一旦所有User Thread离开了,虚拟机也就退出运行了。

  [java] //完成文件输出的守护线程任务

  import java.io.*;

  class TestRunnable implements Runnable{

  public void run(){

  try{

  Thread.sleep(1000);//守护线程阻塞1秒后运行

  File f=new File("daemon.txt");

  FileOutputStream os=new FileOutputStream(f,true);

  os.write("daemon".getBytes());

  }

  catch(IOException e1){

  e1.printStackTrace();

  }

  catch(InterruptedException e2){

  e2.printStackTrace();

  }

  }

  }

  public class TestDemo2{

  public static void main(String[] args) throws InterruptedException

  {

  Runnable tr=new TestRunnable();

  Thread thread=new Thread(tr);

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

  thread.start(); //开始执行分进程

  }

  }

  //运行结果:文件daemon.txt中没有"daemon"字符串。

  //完成文件输出的守护线程任务

  import java.io.*;

  class TestRunnable implements Runnable{

  public void run(){

  try{

  Thread.sleep(1000);//守护线程阻塞1秒后运行

  File f=new File("daemon.txt");

  FileOutputStream os=new FileOutputStream(f,true);

  os.write("daemon".getBytes());

  }

  catch(IOException e1){

  e1.printStackTrace();

  }

  catch(InterruptedException e2){

  e2.printStackTrace();

  }

  }

  }

  public class TestDemo2{

  public static void main(String[] args) throws InterruptedException

  {

  Runnable tr=new TestRunnable();

  Thread thread=new Thread(tr);

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

  thread.start(); //开始执行分进程

  }

  }

  //运行结果:文件daemon.txt中没有"daemon"字符串。

  看到了吧,把输入输出逻辑包装进守护线程多么的可怕,字符串并没有写入指定文件。原因也很简单,直到主线程完成,守护线程仍处于1秒的阻塞状态。这个时候主线程很快就运行完了,虚拟机退出,Daemon停止服务,输出操作自然失败了。

  [java] 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();

  }

  }

  }

  }

0 个回复

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