首页 > 代码库 > 多线程之线程初始

多线程之线程初始

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

      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的层面讲)


总之这一章主要是希望让大家明确线程究竟有哪些熟悉。怎样初始。

多线程之线程初始