概述
多线程之线程初始
上章我们讲了线程的概念,这章我们来深入的了解下一个线程整个初始的过程,感谢上次小伙伴们的意见,后面我都会是文字+图片+代码,让大家看的更轻松。
创建一个线程的代码为:
Thread t = new Thread();
但这仅仅只是初始了一个线程(它目前还什么都不知道只是静静的“坐”在一边),我们来看看这个初始中具体做了哪些事情:
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
可以看到创建线程就是调用了一个初始的方法,再看看每个参数的解释:
1 param g the Thread group
2 param target the object whose run() method gets called
3 param name the name of the new Thread
4 param stackSize the desired stack size for the new thread, or
zero to indicate that this parameter is to be ignored.
第一个参数就是一个线程组,他的作用就是来方便对线程的统一管理,每一个线程都要归属于一个线程组,如果我们不去明确的制定,那么就归属到默认线程组,当然不管是哪个线程组最终都归属于系统线程组,
若创建多个线程而不指定一个组,它们就会自动归属于系统线程组。
第2个参数是调用run()方法的对象,也就是任务对象本身。
第3个创建线程的名称,
第4个就是堆栈的默认分配空间(默认值是0)
JDK中重载了很多创建线程的方法,但是具体实现的过程是大同小异:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
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();
this.name = name.toCharArray();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext = AccessController.getContext();
this.target = target;
setPriority(priority);
if (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();
}
首先会拿到当前线程的对象的引用,然后分配一个线程组(默认线程组选择权最低,参数的选择权最高),然后就是一系列给属性赋值的操作。这里就不细说了,其中有一些重要的属性来说明下:
/* Whether or not to single_step this thread. */
private boolean single_step;
是否为一个简单的线程
/* Whether or not the thread is a daemon thread. */
private boolean daemon = false;
是否是后台线程,
Daemon的作用是为其他线程的运行提供服务,比如说GC线程。其实User Thread线程和Daemon Thread守护线程本质上来说去没啥区别的,唯一的区别之处就在虚拟机的离开:如果User Thread全部撤离,那么Daemon Thread也就没啥线程好服务的了,所以虚拟机也就退出了。
/* JVM state */
private boolean stillborn = false;
是否为激活状态,对于线程的状态我们后面会详细的介绍
/* What will be run. */
private Runnable target;
任务实体类对象,具体任务放在继续Runnable接口的run()方法中
/* The group of this thread */
private ThreadGroup group;
线程组
/* The context ClassLoader for this thread */
private ClassLoader contextClassLoader;
线程上下文的加载器
/* The inherited AccessControlContext of this thread */
private AccessControlContext inheritedAccessControlContext;
这里是继承
AccessControlContext类()
这里才是真正的线程,而等到线程的方法就是:
this.inheritedAccessControlContext = AccessController.getContext();
this.inheritedAccessControlContext = AccessController.getContext();
其实这里是用一种调用当前上下文的快照的技术,而我们通常使用的dubug对象也是在
AccessController类中,代码:
public final class AccessControlContext {
public final class AccessControlContext {
private ProtectionDomain context[];
private boolean isPrivileged;
private AccessControlContext privilegedContext;
private DomainCombiner combiner = null;
private static boolean debugInit = false;
private static Debug debug = null;
static Debug getDebug()
{
if (debugInit)
return debug;
else {
if (Policy.isSet()) {
debug = Debug.getInstance("access");
debugInit = true;
}
return debug;
}
}
/* For autonumbering anonymous threads. */
private static int threadInitNumber;
这里就是为线程id命名的一个id(是线程id组成的一部分,线程id的结构是“Thread-”+
threadInitNumber
),这id也是自增的,代码:
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
而在线程初始的时候就给了id,代码:
tid = nextThreadID();
private long stackSize;
堆栈空间,默认jvm会分配
private long tid;
线程id
/* Java thread status for tools,
* initialized to indicate thread 'not yet started'
*/
private int threadStatus = 0;
线程状态,可惜的是没备注所有的状态解释和对应的状态值
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
最小线程的优先权
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
默认线程的优先权
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
最大线程的优先权
大致就这些吧,以上是线程中比较重要线程的属性,这会有助于我们跟好的去理解线程的组成和机制
其实以上仅仅只是说明了线程在jdk层的初始,但从一台电脑来讲,整个线程创建的流程是怎样了?
大家都知道在java层调度操作系统时中间还有一层jvm,这里本人也没去深究jvm和操作系统之间的通讯,但大致画出了一个创建线程的流程图:
在我们工作中我们实际还是从线程池中去拿,而这又涉及到对线程池工作原理的了解,但在这章我们不做讲解。(从jdk的层面讲)
总之这一章主要是希望让大家明白线程到底有哪些熟悉,如何初始。
最后
以上就是斯文蛋挞为你收集整理的多线程之线程初始的全部内容,希望文章能够帮你解决多线程之线程初始所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复