线程设置为守护线程的过程之源码分析
1 守护线程和用户线程的区别
1.1线程分为用户线程和守护线程,默认都是用户线程
1.2虚拟机必须确保用户线程执行完毕,但是不会等待守护线程执行完毕
1.3守护线程使用场景:操作日志 监控内存 垃圾回收
1.4当用户线程结束,守护线程也会跟着结束
2 守护线程是怎么创建的
2.1设置为守护线程的方法setDaemon,默认是传false,默认是用户线程,调用这个方法即可将线程设置为守护线程
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
3 在设置线程为守护的线程的过程,会检验这个线程是否已经启动,已经是否有权限修改
checkAccess(); 校验权限
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
判断线程是否存活,因此要在启动之前设置守护线程标识,如果已经启动则无法设置,抛出异常
throw new IllegalThreadStateException();
public final native boolean isAlive();
守护线程和用户线程的初始化过程都是一模一样的,相同的init方法,并默认设置为用户线程
线程在初始化的时候,会调用判断,是否是守护线程,默认是false,而且此时一定是false,创建对象的过程init方法如下:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
判断是否为守护线程的方法isDaemon
/**
* Tests if this thread is a daemon thread.
*
* @return <code>true</code> if this thread is a daemon thread;
* <code>false</code> otherwise.
* @see #setDaemon(boolean)
*/
public final boolean isDaemon() {
return daemon;
}
打断点测试
初始化时,赋值 this.daemon = parent.isDaemon();
创建对象成功之后,调用方法赋值,标记为守护线程,修改Thread的对象的值
初始化方法都是在构造对象的时候使用,没有其他的地方调用执行
那么问题来了?初始花的时候为什么是调用判断是否守护方法,而不是直接赋值为false? ?
总结:个人认为守护线程和用户线程在创建的过程没有区别,如果是守护线程,在启动之前对线程对象修改了值,标记为守护线程,
那么这个线程优先级低,同时若JVM中所有的用户线程执行结束,则守护线程会跟随停止,不能保证守护线程的任务正常结束
那么是否有一种场景,我希望他是守护线程,同时我还希望守护线程的任务正常结束,在jvm关闭之前完成任务?
这个答案下期见
以上文章为个人学习记录,若有任何不正确的地方,欢迎指正!