您的位置:首页 > 编程语言 > Java开发

Java中的守护线程 & 非守护线程(简介)

2012-10-31 15:49 253 查看
守护线程 (Daemon Thread)

非守护线程,又称用户线程(User Thread)

用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆:只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。

守护线程最典型的应用就是 GC (垃圾回收器)

守护线程通常是由虚拟机自行创建使用,不过通过编码同样可以创建守护线程,而且 very easy:

Thread daemonTread = new Thread();

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

daemonThread.setDaemon(true);

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

daemonThread.isDaemon();

守护线程与普通线程的唯一区别是:当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则不会退出。(以上是针对正常退出,调用System.exit则必定会退出)

所以setDeamon(true)的唯一意义就是告诉JVM不需要等待它退出,让JVM喜欢什么退出就退出吧,不用管它。

//下面是一个例子

守护线程与普通线程写法上基本么啥区别,调用线程对象的方法setDaemon(true),则可以将其设置为守护线程。

守护线程使用的情况较少,但并非无用,举例来说,JVM的垃圾回收、内存管理等线程都是守护线程。还有就是在做数据库应用时候,使用的数据库连接池,连接池本身也包含着很多后台线程,监控连接个数、超时时间、状态等等。

setDaemon方法的详细说明:

public final void setDaemon( boolean on)将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。

该方法必须在启动线程前调用。

该方法首先调用该线程的 checkAccess 方法,且不带任何参数。这可能抛出 SecurityException(在当前线程中)。

参数:

on - 如果为 true,则将该线程标记为守护线程。

抛出:

IllegalThreadStateException - 如果该线程处于活动状态。

SecurityException - 如果当前线程无法修改该线程。

另请参见:

isDaemon(), checkAccess()

/**

* Java线程:线程的调度-守护线程

*

* @author leizhimin 2009-11-4 9:02:40

*/

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();

}

}

}

}

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
从上面的执行结果可以看出:

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

java的守护线程

线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread 对 象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。
当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的 main 方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:
· 调用了 Runtime 类的 exit 方法,并且安全管理器允许退出操作发生。
· 非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到 run 方 法之外的异常。
在JAVA中守护线程就是调用了SETDAEMON()方法的线程,即后台线程.
这个方法的调用要在START()方法之前(这是必须的:因为一个线程创建的时候,默认的是前台线程);
守护线程的功能:
为非后台线程服务。(例如垃圾回收的精灵线程)
如果前台线程全部结束,则后台线程也随即结束,然后JVM退出;否则后台的守护线程将一直执行。
Java线程的管理

线程的状态控制

在这里需要明确的是:无论采用继承 Thread类还是实现Runnable接口来实现应用程序的多线程能力,都需要在该类中定义用于完成实际功能的run方法,这个run方法称为线程体 (Thread Body)。按照线程体在计算机系统内存中的状态不同,可以将线程分为创建、就绪、运行、睡眠、挂起和死亡等类型。这些线程状态类型下线程的特征为:

创建状态:当利用new关键字创建线程对象实例后,它仅仅作为一个对象实例存在,JVM没有为其分配CPU时间片等线程运行资源;

就绪状态:在处于创建状态的线程中调用start方法将线程的状态转换为就绪状态。这时,线程已经得到除CPU时间之外的其它系统资源, 只等JVM的线程调度器按照线程的优先级对该线程进行调度,从而使该线程拥有能够获得CPU时间片的机会。

睡眠状态:在线程 运行过程中可以调用sleep方法并在方法参数中指定线程的睡眠时间将线程状态转换为睡眠状态。这时,该线程在不释放占用资源的情况下停止运行指定的睡眠 时间。时间到达后,线程重新由JVM线程调度器进行调度和管理。

挂起状态:可以通过调用suspend方法将线程的状态转换 为挂起状态。这时,线程将释放占用的所有资源,由JVM调度转入临时存储空间,直至应用程序调用resume方法恢复线程运行。

死亡状态:当线程体运行结束或者调用线程对象的stop方法后线程将终止运行,由JVM收回线程占用的资源。

在Java线 程类中分别定义了相应的方法,用于在应用程序中对线程状态进行控制和管理。

线程的调度

线程调用 的意义在于JVM应对运行的多个线程进行系统级的协调,以避免多个线程争用有限资源而导致应用系统死机或者崩溃。

为了线程对 于操作系统和用户的重要性区分开,Java定义了线程的优先级策略。Java将线程的优先级分为10个等级,分别用1-10之间的数字表示。数字越大表明 线程的级别越高。相应地,在Thread类中定义了表示线程最低、最高和普通优先级的成员变量MIN_PRIORITY、MAX_PRIORITY和 NORMAL_PRIORITY,代表的优先级等级分别为1、10和5。当一个线程对象被创建时,其默认的线程优先级是5。

为了控制线程的运行策略,Java定义了线程调度器来监控系统中处于就绪状态的所有线程。线程调度器按照线程的优先级决定那个线程投入处理器运行。在多个 线程处于就绪状态的条件下,具有高优先级的线程会在低优先级线程之前得到执行。线程调度器同样采用"抢占式"策略来调度线程执行,即当前线程执行过程中有 较高优先级的线程进入就绪状态,则高优先级的线程立即被调度执行。具有相同优先级的所有线程采用轮转的方式来共同分配CPU时间片。

在应用程序中设置线程优先级的方法很简单,在创建线程对象之后可以调用线程对象的setPriority方法改变该线程的运行优先级,同样可以调用 getPriority方法获取当前线程的优先级。

在Java中比较特殊的线程是被称为守护(Daemon)线程的低级别线 程。这个线程具有最低的优先级,用于为系统中的其它对象和线程提供服务。将一个用户线程设置为守护线程的方式是在线程对象创建之前调用线程对象的 setDaemon方法。典型的守护线程例子是JVM中的系统资源自动回收线程,它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。

线程分组管理

Java定义了在多线程运行系统中的线程组(ThreadGroup)对象,用于实现按照特定 功能对线程进行集中式分组管理。用户创建的每个线程均属于某线程组,这个线程组可以在线程创建时指定,也可以不指定线程组以使该线程处于默认的线程组之 中。但是,一旦线程加入某线程组,该线程就一直存在于该线程组中直至线程死亡,不能在中途改变线程所属的线程组。

当Java 的Application应用程序运行时,JVM创建名称为main的线程组。除非单独指定,在该应用程序中创建的线程均属于main线程组。在main 线程组中可以创建其它名称的线程组并将其它线程加入到该线程组中,依此类推,构成线程和线程组之间的树型管理和继承关系。

与 线程类似,可以针对线程组对象进行线程组的调度、状态管理以及优先级设置等。在对线程组进行管理过程中,加入到某线程组中的所有线程均被看作统一的对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: