xl_echo编辑整理,欢迎转载,转载请声明文章来源。更多IT、编程案例、资料请联系QQ:1280023003,加群298140694。百战不败,依不自称常胜,百败不颓,依能奋力前行。——这才是真正的堪称强大!!


在之前的文章中我们对多线程和实现线程等基础知识有了一定的了解,这个时候我们就可以继续深入的了解一下线程的实现,Thread的构造

Thread的构造

我们可以通过创建一个类,继承Tread来,然后查看Tread的底层实现。可以看到Thread类的构造方法被重载了八次,陈列如下:

public Thread(){init(null, null, "Thread-" + nextThreadNum(), 0);};
public Thread(Runnable target){init(null, target, "Thread-" + nextThreadNum(), 0);};
public Thread(String name){init(group, target, "Thread-" + nextThreadNum(), 0);};
public Thread(Runnable target, String name){init(null, null, name, 0);};
public Thread(ThreadGroup group, Runnable target){init(group, null, name, 0);};
public Thread(ThreadGroup group, String name){init(null, target, name, 0);};
public Thread(ThreadGroup group, Runnable target, String name){init(group, target, name, 0);};
public Thread(ThreadGroup group, Runnable target, String name, long stackSize){init(group, target, name, stackSize);};

构造方法中几个参数的作用

  • Runnable target

实现了Runnable接口的类的实例。要注意的是Thread类也实现了Runnable接口,因此,从Thread类继承的类的实例也可以作为target传入这个构造方法。

  • String name

线程的名字。这个名字可以在建立Thread实例后通过Thread类的setName方法设置。如果不设置线程的名子,线程就使用默认的线程名:Thread-N,N是线程建立的顺序自增变量,是一个不重复的正整数。在我们的源码中可以看到他的实现:

public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}

private static int threadInitNumber;
private static synchronized int nextThreadNum() {
    return threadInitNumber++;
}
  • ThreadGroup group

当前建立的线程所属的线程组。如果不指定线程组,所有的线程都被加到一个默认的线程组中。关于线程组的细节将在后面的章节详细讨论。

  • long stackSize

线程栈的大小,这个值一般是CPU页面的整数倍。如x86的页面大小是4KB。在x86平台下,默认的线程栈大小是12KB。

线程的继承

在我们之前多线程实现中,我们看到输出结果都有一个main,原因其实很简单。其实不难看出,一个线程的创建时由另外一个线程完成的。我们之前的线程一开始是只有main线程,main线程是JVM创建的,这反证了我们这个观点。(请不要纠结源头是谁,这种问题要么就是进入到鸡生蛋蛋生鸡的循环中去,要么就是要扯到远古)

创建线程的时候,我们也可以看到我们线程的父线程。

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();
    }

其中currentThread(); 就是在创建新线程的时候获取当前线程来做新建的操作。

既然可以继承,可以到某一个线程组里面,那么我们就应该可以自己将新线程加入到某个线程组

我们之前的构造方法当中就有实现我们这个需求的重载方法。只需要在我们创建线程的时候,传入一个ThreadGroup group 就指定了需要计入的线程组。