我是靠谱客的博主 斯文蛋挞,最近开发中收集的这篇文章主要介绍多线程之线程初始,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

                                                                     多线程之线程初始
  上章我们讲了线程的概念,这章我们来深入的了解下一个线程整个初始的过程,感谢上次小伙伴们的意见,后面我都会是文字+图片+代码,让大家看的更轻松。
        创建一个线程的代码为:

      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();
其实这里是用一种调用当前上下文的快照的技术,而我们通常使用的dubug对象也是在 AccessController类中,代码:
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的层面讲)

总之这一章主要是希望让大家明白线程到底有哪些熟悉,如何初始。

最后

以上就是斯文蛋挞为你收集整理的多线程之线程初始的全部内容,希望文章能够帮你解决多线程之线程初始所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部