守护线程和非守护线程_java守护线程的作用

守护线程和非守护线程_java守护线程的作用Java中有两类线程:UserThread(用户线程)、DaemonThread(守护线程)用户线程即运行在前台的线程,而守护线程是运行在后台的线程。守护线程作用是为其他前台线程的运行提供便利服务,而且仅在普通、非守护线程仍然运行时才需要,比如垃圾回收线程就是一个守护线程。当VM检测仅剩一个守护线程,而用户线程都已经退出运行时,VM就会退出,因为没有如果没有了被守护这,也就没有继续运行程…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

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

用户线程即运行在前台的线程,而守护线程是运行在后台的线程。 守护线程作用是为其他前台线程的运行提供便利服务,而且仅在普通、非守护线程仍然运行时才需要,比如垃圾回收线程就是一个守护线程。当VM检测仅剩一个守护线程,而用户线程都已经退出运行时,VM就会退出,因为没有如果没有了被守护这,也就没有继续运行程序的必要了。如果有非守护线程仍然存活,VM就不会退出。

守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程。用户可以用Thread的setDaemon(true)方法设置当前线程为守护线程。

虽然守护线程可能非常有用,但必须小心确保其他所有非守护线程消亡时,不会由于它的终止而产生任何危害。因为你不可能知道在所有的用户线程退出运行前,守护线程是否已经完成了预期的服务任务。一旦所有的用户线程退出了,虚拟机也就退出运行了。 因此,不要在守护线程中执行业务逻辑操作(比如对数据的读写等)。、

另外有几点需要注意:

1、setDaemon(true)必须在调用线程的start()方法之前设置,否则会抛出IllegalThreadStateException异常。

2、在守护线程中产生的新线程也是守护线程。
3、 不要认为所有的应用都可以分配给守护线程来进行服务,比如读写操作或者计算逻辑。

Timer代码示例:

package day003;

import java.util.Date;
import java.util.TimerTask;

/**
*
* 项目名称:JavaThread
* 类名称:MyTask
* 类描述:
* 创建人:liuc
* 创建时间:2018年3月19日 下午3:05:28
* 修改人:liuc
* 修改时间:2018年3月19日 下午3:05:28
* 修改备注:
* @version
*
*/
public class MyTask extends TimerTask{

	/**
	* (non-Javadoc)
	* @see java.util.TimerTask#run()
	*/
	public void run() {
		 System.out.println("任务执行了,时间为:"+new Date());
	}
}
-----------------------------------------------------------------------------------
package day003;

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;

/**
*
* 项目名称:JavaThread
* 类名称:TimerTaskRun
* 类描述:
* 创建人:liuc
* 创建时间:2018年3月19日 下午3:08:01
* 修改人:liuc
* 修改时间:2018年3月19日 下午3:08:01
* 修改备注:
* @version
*
*/
public class TimerTaskRun {
	public static void main(String[] args) {
		System.out.println("系统当前时间:"+new Date());
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.SECOND, 10);
		Date date = calendar.getTime();
		MyTask task = new MyTask();
		Timer timer = new Timer();
		timer.schedule(task, date);
	}
}

运行结果:

系统当前时间:Mon Mar 19 15:11:47 CST 2018
任务执行了,时间为:Mon Mar 19 15:11:57 CST 2018

任务虽然运行完了,但进程还未销毁,呈红色状态,为什么会出现这种情况呢?
这里写图片描述

可以看一下Timer的源码

   /**
     * Creates a new timer.  The associated thread does <i>not</i>
     * {@linkplain Thread#setDaemon run as a daemon}.
     */
    public Timer() {
        this("Timer-" + serialNumber());
    }


   /**
     * Creates a new timer whose associated thread has the specified name.
     * The associated thread does <i>not</i>
     * {@linkplain Thread#setDaemon run as a daemon}.
     *
     * @param name the name of the associated thread
     * @throws NullPointerException if {@code name} is null
     * @since 1.5
     */
    public Timer(String name) {
        thread.setName(name);
        thread.start();
    }

可以看出每创建一个Timer就是启动一个新的线程,那么启动的线程不是守护线程,所以一直运行。那我们该如何将 新创建的的Timer改成守护线程呢?更改如上的代码:

package day003;

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;

/**
*
* 项目名称:JavaThread
* 类名称:TimerTaskRun
* 类描述:
* 创建人:liuc
* 创建时间:2018年3月19日 下午3:08:01
* 修改人:liuc
* 修改时间:2018年3月19日 下午3:08:01
* 修改备注:
* @version
*
*/
public class TimerTaskRun {
	public static void main(String[] args) {
		System.out.println("系统当前时间:"+new Date());
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.SECOND, 10);
		Date date = calendar.getTime();
		MyTask task = new MyTask();
		Timer timer = new Timer(true);
		timer.schedule(task, date);
	}
}

运行结果如下:
系统当前时间:Mon Mar 19 15:21:42 CST 2018
这里写图片描述

守护线程中产生的线程也是守护线程
如下示例:

package day003;

/**
*
* 项目名称:JavaThread
* 类名称:Daemon
* 类描述:
* 创建人:liuc
* 创建时间:2018年3月19日 下午3:30:53
* 修改人:liuc
* 修改时间:2018年3月19日 下午3:30:53
* 修改备注:
* @version
*
*/
public class Daemon implements Runnable {
	private Thread[] t = new Thread[10];

	/**
	* (non-Javadoc)
	* @see java.lang.Runnable#run()
	*/
	public void run() {
		for (int i = 0; i < t.length; i++) {
			t[i] = new Thread(new DaemonSpawn());
			t[i].start();
			System.out.println("DaemonSpawn " + i + " started.");
		}
		for (int i = 0; i < t.length; i++) {
			System.out.println("t[" + i + "].isDaemon() = " + t[i].isDaemon() + ".");
		}
		while (true) {
			Thread.yield();
		}
	}
}
-----------------------------------------------------------------------------------
package day003;

/**
*
* 项目名称:JavaThread
* 类名称:DaemonSpawn
* 类描述:
* 创建人:liuc
* 创建时间:2018年3月19日 下午3:32:06
* 修改人:liuc
* 修改时间:2018年3月19日 下午3:32:06
* 修改备注:
* @version
*
*/
public class DaemonSpawn implements Runnable {

	/**
	* (non-Javadoc)
	* @see java.lang.Runnable#run()
	*/
	public void run() {
		while (true) {
			Thread.yield();
		}
	}
}
-----------------------------------------------------------------------------------
package day003;

import java.util.concurrent.TimeUnit;
/**
*
* 项目名称:JavaThread
* 类名称:DaemonRun
* 类描述:
* 创建人:liuc
* 创建时间:2018年3月19日 下午3:36:34
* 修改人:liuc
* 修改时间:2018年3月19日 下午3:36:34
* 修改备注:
* @version
*
*/
public class DaemonRun {
	public static void main(String[] args) throws InterruptedException {
		Thread d = new Thread(new Daemon());
		d.setDaemon(true);//必须在启动线程前调用
		d.start();
		System.out.println("d.isDaemon() = " + d.isDaemon() + ".");
	    TimeUnit.SECONDS.sleep(1);
	}
}

运行结果如图:

d.isDaemon() = true.
DaemonSpawn 0 started.
DaemonSpawn 1 started.
DaemonSpawn 2 started.
DaemonSpawn 3 started.
DaemonSpawn 4 started.
DaemonSpawn 5 started.
DaemonSpawn 6 started.
DaemonSpawn 7 started.
DaemonSpawn 8 started.
DaemonSpawn 9 started.
t[0].isDaemon() = true.
t[1].isDaemon() = true.
t[2].isDaemon() = true.
t[3].isDaemon() = true.
t[4].isDaemon() = true.
t[5].isDaemon() = true.
t[6].isDaemon() = true.
t[7].isDaemon() = true.
t[8].isDaemon() = true.
t[9].isDaemon() = true.

如果将mian函数中的TimeUnit.SECONDS.sleep(1);注释掉,看一下TimeUnit.SECONDS.sleep()的源码:

/**
     * Performs a {@link Thread#sleep(long, int) Thread.sleep} using
     * this time unit.
     * This is a convenience method that converts time arguments into the
     * form required by the {@code Thread.sleep} method.
     *
     * @param timeout the minimum time to sleep. If less than
     * or equal to zero, do not sleep at all.
     * @throws InterruptedException if interrupted while sleeping
     */
    public void sleep(long timeout) throws InterruptedException {
        if (timeout > 0) {
            long ms = toMillis(timeout);
            int ns = excessNanos(timeout, ms);
            Thread.sleep(ms, ns);
        }
    }

其实就是对Thread.sleep()的封装,提供了可读性更好的线程暂停操作
注释后代码运行如下:

d.isDaemon() = true.

以上结果也说明了如果用户线程全部退出了,只剩下守护线程存在了,虚拟机也就退出了。

典型的守护线程是(GC)垃圾回收线程。

package day003;


/**
*
* 项目名称:JavaThread
* 类名称:MyThread
* 类描述:
* 创建人:liuc
* 创建时间:2018年3月19日 下午3:50:12
* 修改人:liuc
* 修改时间:2018年3月19日 下午3:50:12
* 修改备注:
* @version
*
*/
public class MyThread extends Thread{
	private int i = 0;
	/**
	* (non-Javadoc)
	* @see java.lang.Thread#run()
	*/
	
	public void run() {
		super.run();
		try {
			while (true) {
				i++;
				System.out.println("i="+i);
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	public static void main(String[] args) throws InterruptedException {
		MyThread daemonThread = new MyThread();
		daemonThread.setDaemon(true);
		daemonThread.start();
		Thread.sleep(5000);
		System.out.println("当main线程执行完毕,守护线程也停止了。");
	}
}

运行结果:

i=1
i=2
i=3
i=4
i=5
当main线程执行完毕,守护线程也停止了。

除 JVM 内部的守护线程外,用户可以通过以下方法设置守护线程:

public final void setDaemon(boolean on)

可以通过以下方法查询线程是否为守护线程:

public final boolean isDaemon()

关于守护线程的几个要点:
1、setDaemon 方法必须在 thread.start() 之前设置,否则会抛出 java.lang.IllegalThreadStateException 异常,不能将正在运行的常规线程设置为守护线程

package day003;

/**
*
* 项目名称:JavaThread
* 类名称:TestDaemon
* 类描述:
* 创建人:liuc
* 创建时间:2018年3月19日 下午4:01:32
* 修改人:liuc
* 修改时间:2018年3月19日 下午4:01:32
* 修改备注:
* @version
*
*/
public class TestDaemon {
	public static void main(String[] args) {
	    Thread thread = new Thread();
	    thread.start();
	    thread.setDaemon(true);
	}
}

运行结果:

Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.setDaemon(Thread.java:1359)
	at day003.TestDaemon.main(TestDaemon.java:32)

2、不是所有的应用都可以分配给 Daemon 线程来进行服务,比如读写操作或者计算逻辑,因为在 Daemon 线程还没来的及进行操作时虚拟机可能已经退出了

package day003;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
*
* 项目名称:JavaThread
* 类名称:TestDaemon2
* 类描述:
* 创建人:liuc
* 创建时间:2018年3月19日 下午4:03:22
* 修改人:liuc
* 修改时间:2018年3月19日 下午4:03:22
* 修改备注:
* @version
*
*/
public class TestDaemon2 extends Thread{
	
	/**
	* (non-Javadoc)
	* @see java.lang.Thread#run()
	*/
	
	public void run() {
		super.run();
		FileOutputStream outputStream = null;
        try {
            Thread.sleep(3000);
            File file = new File("daemon.txt");
            outputStream = new FileOutputStream(file);
            outputStream.write("daemon".getBytes());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
	public static void main(String[] args) {
	    Thread thread = new TestDaemon2();
	    thread.setDaemon(true);
	    thread.start();
	}
}

以上代码中线程功能是向工程根目录的“daemon.txt”文件写入字符串“daemon”,实际运行结果发现并未成功写入,且未报任何错误,原因是写入文件的线程被设置为守护线程,该线程还在 sleep 过程中时所有用户线程就全部结束了,守护线程也会随着 JVM 一起退出。

如果将上面代码中的thread.setDaemon(true);注释掉,

	public static void main(String[] args) {
	    Thread thread = new TestDaemon2();
	  //thread.setDaemon(true);
	    thread.start();
	}

不将线程设置为守护线程可以在工程根目录的“daemon.txt”文件中看到字符串“daemon”
这里写图片描述

示例2:

package day003;

/**
*
* 项目名称:JavaThread
* 类名称:CustomThread
* 类描述:
* 创建人:liuc
* 创建时间:2018年3月19日 下午4:16:42
* 修改人:liuc
* 修改时间:2018年3月19日 下午4:16:42
* 修改备注:
* @version
*
*/
public class CustomThread extends Thread {

	/**
	* (non-Javadoc)
	* @see java.lang.Thread#run()
	*/
	public void run() {
		super.run();
		for (int i = 0; i < 100; i++) {
			System.out.println("Daemon Thread : " + i);
		}
	}

	public static void main(String[] args) {
		Thread daemonThread = new CustomThread();
		daemonThread.setDaemon(true);
		Thread userThread = new Thread();
		daemonThread.start();
		userThread.start();
	}
}

多次执行示例2代码,控制台要么不打印任何信息,要么打印一部分循环的输出信息就结束了,从运行结果可以看出,守护线程并未执行完成所有循环就结束了,因为用户线程在守护线程执行循环的过程中就已全部结束,守护线程也随着 JVM 一起结束。

请关注我个人学习的公众号,公众号会不定期发布个人学习的内容记录!
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/181681.html原文链接:https://javaforall.net

(0)
上一篇 2022年10月15日 下午4:00
下一篇 2022年10月15日 下午4:00


相关推荐

  • win10安装vmware虚拟机蓝屏_安装完mac虚拟机出现蓝屏

    win10安装vmware虚拟机蓝屏_安装完mac虚拟机出现蓝屏我们在创建虚拟机的时候,选择的是去创建一个默认的虚拟机,然后创建完成直接将系统装在了这个虚拟机中而这,就是这个问题的所在,对于网上下载的sp3_iso系统来讲,是需要一个ida的硬盘,就是要将虚拟机的硬盘模式重新设置一下对当前虚拟机进行设置,将原来的硬盘删除掉,重新添加HardDisk(也就是硬盘的意思)我们选择这个HardDisk选项,点击下一步然后我们出现了这样一…

    2022年8月16日
    8
  • 中国移动DNS大全「建议收藏」

    中国移动DNSIP地址,包括广东移动DNS,上海移动DNS,北京移动DNS,陕西移动DNS,江苏移动,山东移动DNS等共全国32个移动省份的DNSIP地址。DNS用户数国家省份地区运营商用户数排名(省份)用户数比例(省份)112.4.0.551111900中国陕西西安移动59.84%221.131.143.691022100中国…

    2022年4月15日
    941
  • sse java_SSE详解

    sse java_SSE详解SSE Server SentEvents 通俗解释起来就是一种基于 HTTP 的 以流的形式由服务端持续向客户端发送数据的技术应用场景由于 HTTP 是无状态的传输协议 每次请求需由客户端向服务端建立连接 HTTPS 还需要交换秘钥 所以一次请求 建立连接的过程占了很大比例在 http1 1 中 1 0 也有但未写入标准 虽然增加了 keep alive 来保持和服务器的长连接 省去了很多建立连接的过程 但通

    2026年3月19日
    2
  • java 对象转map,去掉null

    java 对象转map,去掉nullpublicstaticMap&lt;String,Object&gt;beanToMap(Objectobject){Map&lt;String,Object&gt;map=null;try{map=newHashMap&lt;String,Object&gt;();Bean…

    2022年5月7日
    262
  • 第二章:书写Vue组件

    第二章:书写Vue组件第一步 在 sa view 目中新建模块 ddusers 新建一个 vue 组件 ddusers add vue 注意引入其他 vue 组件的方式 不再是 import 而是使用 httpVueLoade 来进行引入 template div el inputv model param name placeholder 姓名 el inputv model param name placeholder 姓名 div template

    2026年3月19日
    1
  • 老生常谈–什么是装箱什么是拆箱「建议收藏」

    老生常谈–什么是装箱什么是拆箱「建议收藏」我们知道.NET具有两个数据类型:值类型和引用类型。因为值类型没有指针引用,不是分配在托管堆中,也不会被GC回收,因此它比引用类型更加高效。但有时我们需要将一种类型的变量转换为另一种类型,这时我们就可以使用装箱/拆箱。一、什么是装箱装箱就是将值类型的数据存储在引用类型的变量中。例如在方法中创建了int类型的变量,需要将这个值类型赋值给一个引用类型的变量,这就意味着对这个值进行了装箱操作,代码如下:voiddemo(){intnum=25;//这是装箱操作objectobjN

    2022年10月21日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号