Java中的守护线程是什么?

909

有人能告诉我 Java 中的守护线程是什么吗?


24
Thread javadoc描述了它们是什么:http://java.sun.com/javase/6/docs/api/java/lang/Thread.html - skaffman
1
http://www.answers.com/Q/What_is_a_daemon_thread - Robb Tsang
3
对于守护线程来说,当JVM停止时,所有的守护线程都会退出。因此,不应经常使用守护线程,因为可能无法对它们进行清理。例如,任何I/O操作都不能优雅地退出并完全写入/读取到结束。 - msj121
27个回答

708

守护线程是一种不会阻止JVM在程序结束后退出但线程仍在运行的线程。垃圾回收就是一个守护线程的例子。

您可以使用setDaemon(boolean)方法在线程启动之前更改Thread守护属性。


235
为了后人,setDaemon(boolean) 只能在线程启动之前调用。默认情况下,线程会继承其父线程的后台状态。 - Gray
2
“does not prevent the JVM from exiting when the program finishes but the thread is still running” while @sateesh says that “JVM halts any remaining daemon threads are abandoned”. So do daemon threads finish running when JVM exits?当程序结束但线程仍在运行时,“不会阻止JVM退出”,而@sateesh表示“JVM停止任何剩余的守护线程”。那么,当JVM退出时,守护线程是否会完成运行? - Gerald
36
@Gerald,当JVM退出时,所有线程都会被终止。B_erb说,“...当程序完成时。”这意味着,如果程序没有显式地终止JVM,那么当最后一个非守护线程结束时,JVM将自动终止。普通线程定义了“程序退出”的概念,而守护线程则不是。 - Solomon Slow
9
这句话“不会阻止JVM在程序完成时退出,即使守护线程仍在运行”基本上是指启动线程的JVM进程不关心守护线程是否执行完毕,如果所有正常线程都执行完毕,JVM进程将结束自身。 - Bhargav
2
@SolomonSlow 当 JVM 结束时,杀死一个守护线程(例如垃圾回收器)在其仍在工作时会有什么后果?谢谢。 - Venkat Ramakrishnan
显示剩余4条评论

372

以下是一些要点(参考:Java并发编程实战

  • 当创建一个新线程时,它继承了父线程的守护状态。
  • 当所有非守护线程完成后,JVM停止运行,任何剩余的守护线程都会被弃用

    • finally块不会执行
    • 堆栈不会展开 - JVM只是退出。

    由于这个原因,应该谨慎使用守护线程,并且千万不能将它们用于可能执行任何类型的I/O的任务。


5
为什么不应该使用守护线程进行I/O操作?是因为担心未被刷新的缓冲区等问题吗? - Paul Cager
4
@PaulCager 是的,它们也可能在写入/读取过程中被截断。 - Cruncher
56
第二点是无意义的。当JVM停止时,所有线程都会终止并且不会执行任何finally块,无论这些线程是否为守护线程。因此,如果您认为可能有正在运行I/O操作的线程,请不要调用System.exit(…)。唯一的区别是当只剩下守护线程时,JVM将触发自己的终止。 - Holger
14
“stacks are not unwound”是什么意思?(意为:堆栈不被展开) - KKK
3
@ɢʜʘʂʈʀɛɔʘɴ 关于"unwinding stacks"的解释已经有一些了,包括这个:http://flylib.com/books/en/2.254.1.277/1/ - user766353
显示剩余5条评论

200

所有上述答案都很好。这里是一个简单的代码片段,用于说明区别。尝试在setDaemon中使用true和false的每个值。

public class DaemonTest {
    
    public static void main(String[] args) {
        new WorkerThread().start();

        try {
            Thread.sleep(7500);
        } catch (InterruptedException e) {
            // handle here exception
        }

        System.out.println("Main Thread ending") ;
    }

}

class WorkerThread extends Thread {
    
    public WorkerThread() {
        // When false, (i.e. when it's a non daemon thread),
        // the WorkerThread continues to run.
        // When true, (i.e. when it's a daemon thread),
        // the WorkerThread terminates when the main 
        // thread or/and user defined thread(non daemon) terminates.
        setDaemon(true); 
    }
    
    public void run() {
        int count = 0;

        while (true) {
            System.out.println("Hello from Worker "+count++);

            try {
                sleep(5000);
            } catch (InterruptedException e) {
                // handle exception here
            }
        }
    }
}

2
@russ 不错的代码片段!不过我必须将WorkerThread类定义为静态的。 - xli
@xli 你也可以这样做 new DaemonTest().new WorkerThread().start() :) - abhy
@russ 很好的例子。如果您没有明确定义“setDaemon(true)”,则默认值为“setDeamon(false)”。 - huseyin
catch (InterruptException)块中也有类似于println()的东西,这将清楚地表明守护线程不是通过中断机制退出的,而是突然停止存在。 - antak

105

在UNIX中,传统上Daemon进程是那些像Windows服务一样一直在后台运行的进程。

Java中的Daemon线程是指不会阻止JVM退出的线程。具体来说,只有当Daemon线程存在时,JVM才会退出。您可以通过在Thread上调用setDaemon()方法来创建一个Daemon线程。

请阅读有关Daemon线程的内容。


3
你的链接已经失效,或许你想要更新一下?不管怎样,给你一个赞。 - Jasonw
2
我喜欢UNIX和Windows之间的比较。 - Premraj
最好的解释在这里! - LoveMeow

57

守护线程像服务提供者,为运行在同一进程中的其他线程或对象提供支持。守护线程用于后台支持任务,只有在正常线程执行时才需要。如果没有正常线程正在运行且剩余线程都是守护线程,则解释器将退出。

例如,HotJava 浏览器使用最多四个名为“Image Fetcher”的守护线程,为需要图像的任何线程从文件系统或网络获取图像。

守护线程通常用于为应用程序/小程序执行服务(如加载“琐碎的部分”)。用户线程和守护线程之间的核心区别在于,当所有用户线程终止时,JVM 才会关闭程序。当不再运行任何用户线程(包括主执行线程)时,JVM 将终止守护线程。

setDaemon(true/false)? 此方法用于指定线程是否为守护线程。

public boolean isDaemon()? 此方法用于确定线程是否为守护线程。

例如:

public class DaemonThread extends Thread {
    public void run() {
        System.out.println("Entering run method");

        try {
            System.out.println("In run Method: currentThread() is" + Thread.currentThread());

            while (true) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException x) {}

                System.out.println("In run method: woke up again");
            }
        } finally {
            System.out.println("Leaving run Method");
        }
    }
    public static void main(String[] args) {
        System.out.println("Entering main Method");

        DaemonThread t = new DaemonThread();
        t.setDaemon(true);
        t.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException x) {}

        System.out.println("Leaving main method");
    }

}

输出:

C:\java\thread>javac DaemonThread.java

C:\java\thread>java DaemonThread
Entering main Method
Entering run method
In run Method: currentThread() isThread[Thread-0,5,main]
In run method: woke up again
In run method: woke up again
In run method: woke up again
In run method: woke up again
In run method: woke up again
In run method: woke up again
Leaving main method

C:\j2se6\thread>

45

守护进程:来自d(isk) a(nd) e(xecution) mon(itor) 或者de(vice) mon(itor)

守护进程(计算机)的定义:

一种后台进程,处理像打印作业和文件传输等服务请求,并在不需要时处于休眠状态。

—— 来源:牛津字典英语

Java中的守护线程是什么?

  • 守护线程可以在其流程之间随时关闭,而非守护线程即用户线程会完全执行。
  • 守护线程在其他非守护线程运行时会间歇性地在后台运行。
  • 当所有非守护线程完成时,守护线程会自动终止。
  • 守护线程是为在同一进程中运行的用户线程提供服务的。
  • JVM 不关心守护线程何时完成,即使 finally 块也不会执行。JVM 会优先考虑我们创建的非守护线程。
  • 守护线程在 Windows 中充当服务。
  • 当所有用户线程(与守护线程相对)终止时,JVM 停止守护线程。因此,守护线程可用于实现监视功能,因为一旦所有用户线程停止,线程将被 JVM 停止。

如果您调用System.exit(),则无论线程是否为守护线程,都不会执行finally块。实际上,在JVM尚未杀死线程的情况下,即使最后一个用户线程终止,也会在守护线程中执行finally块。 - benez
7
除非在开始执行之前已更改,否则守护线程将以与其创建线程相同的优先级执行。守护线程不一定是“服务提供者”、Windows 服务或此处说明的任何其他内容:它们只是不会防止 JVM 退出的线程。简而言之。 - user207421

38

守护线程是一种被认为在后台执行某些任务的线程,例如处理请求或应用程序中可能存在的各种定时任务。

当程序中只有 守护线程 时,程序将退出。这是因为通常这些线程与普通线程一起工作,并提供事件的后台处理。

您可以使用 setDaemon 方法指定一个Thread守护线程,它们通常不会退出,也不会被中断...当应用程序停止时它们才会停止。


1
这是因为它是一个守护线程,这就是“守护进程”的含义。你的推理是前后颠倒的。 - user207421

16

我想要澄清的一个误解:

  • 假设在用户线程(例如 A)中创建了守护线程(例如 B),那么结束此用户线程/父线程(A)将不会结束其创建的守护线程/子线程(B),前提是用户线程是唯一正在运行的线程。
  • 因此,在线程结束时不存在父子关系。所有守护线程(无论在何处创建)都将在没有单个活动用户线程并导致 JVM 终止时结束。
  • 即使对于两个(父/子)都是守护线程也是如此。
  • 如果从守护线程创建子线程,则该子线程也是守护线程。这不需要任何显式的守护线程标志设置。 同样,如果从用户线程创建子线程,则该子线程也是用户线程,如果您想要更改它,则需要在启动该子线程之前进行显式守护标志设置。

这不是引用自任何内容。对于非引用的文本,请不要使用引用格式。引语的第一段是不正确的,并且与第二段相矛盾。 - user207421
@EJP明白了,所以每个人都必须在这里给其他人报价,而不是自己。或者我们自己在别处报价,然后指向这里? - Kanagavelu Sugumar
是的,如果你引用了某人的话,你必须像其他地方一样引用他们,但如果你没有引用任何人,请不要将其格式化为已引用。我无法理解你的第二个句子。 - user207421

14

守护线程和用户线程。通常情况下,程序员创建的所有线程都是用户线程(除非您指定其为守护线程或者您的父线程是守护线程)。 用户线程通常用于运行我们的程序代码。 JVM直到所有用户线程终止后才会终止。


12

Java拥有一种特殊的线程,称为守护线程。

  • 优先级非常低。
  • 只有在程序中没有运行其他线程时才会执行。
  • 当程序中只有守护线程在运行时,JVM会结束程序并停止这些线程。

守护线程通常用作正常线程的服务提供者。它们通常具有无限循环,等待服务请求或执行线程的任务。它们不能做重要的工作。(因为我们不知道它们何时会有CPU时间,并且如果没有其他线程运行,它们随时可能完成。)

这种线程的典型示例是Java垃圾收集器

还有更多...

  • 只有在调用start()方法之前,才能调用setDaemon()方法设置线程为守护线程。一旦线程开始运行,就不能修改其守护进程状态。
  • 使用isDaemon()方法来检查线程是否为守护线程或用户线程。

8
我不认为守护线程本质上是低优先级的。我看过的所有文档也没有这样说明。此外,这个 Stack Overflow 的答案声称线程的优先级和是否为守护线程是无关的:https://dev59.com/TWPVa4cB1Zd3GeqP2BDb#10298353 - MikeFHay
5
守护线程与优先级无关。你可以有一个高优先级的守护线程或低优先级的非守护线程。 - Gray
一个守护线程最初的优先级与创建它的线程相同。 - user207421
该语句“'仅在同一程序没有其他线程运行时执行”是具有误导性的。 - Fredrick Gauss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接