备注:此文章适合新手入门
接上一篇:Thread之创建线程(2)
今天我门来看一下thread 的内部构造线程执行的过程,以下是所有的构造函数。
/**
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, null, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
接下来我们先来看下Thread的命名规则
这里有个被static修饰的值,在jvm启动时被初始化,后面创建线程就++;这样我们就知道线程的默认名的由来了,Thread对象.getName()为什么会这种样式了,例如:thread-0,thread-1....,而如果你使用public Thread(String name),这个构造方法,传入的值将作为此线程的名字,当然nextThreadNum()也就不会生效,执行自身递增
/* For autonumbering anonymous threads. */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
我们接着来看下init方法都做了什么
/**
* Initializes a Thread with the current AccessControlContext.
* @see #init(ThreadGroup,Runnable,String,long,AccessControlContext)
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null);
}
看注释这里是初始化一个Thread,上面我们看init方法需要传入4个类型的参数:
ThreadGroup g:线程组
Runnable target:目标所需执行资源
String name:线程名
long stackSize:栈的大小
这里我们前面在构造Thread 时传递 的参数的作用在这里生效
下面是Runable作为参数传进去
Thread( Runnable target, String name)
Thread( Runnable target)
Thread ss = new Thread(new Runnable() {
@Override
public void run() {
//操作执行单元
System.out.println(Thread.currentThread().getName());
}
},"myThread-1");
ss.start();
当然,也可以使用java8的Lambda表达式方式构造:
Thread ss = new Thread(()->{
//操作执行单元
System.out.println(Thread.currentThread().getName());
},"myThread-1");
ss.start();
那么,我们明白了传name和Runnable组合的构造函数,那么重点来了,我们来看第三种,带有ThreadGroup的方式,
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, String name)
首先明确什么是ThreadGroup:
线程组表示一个线程的集合。此外,线程组也可以包含其他线程组。线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组。
允许线程访问有关自己的线程组的信息,但是不允许它访问有关其线程组的父线程组或其他任何线程组的信息。(摘自jdk1.6)
讲线程加入线程组之后,方便对其进行管理(获取安全策略,统一设置线程优先级等,设置线程),一般根线程为system,再往下为main线程组,一般在创建线程时未指定线程组,则默认为main线程组所属。线程和线程组的关系就相当于一个子节点和一个二叉树的关系。
首先我们假设,如果不传ThreadGroup进去,那么 在init里会做什么操作呢???
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();
}
}
sercurity这里我们先暂时不用管,我们来看下面
g = parent.getThreadGroup();
这里把g赋值为当前线程父类所属的ThreadGroup。
//获取当前线程所在线程组内 的线程存活的个数
System.out.println(Thread.currentThread().getThreadGroup().activeCount());
//获取当前线程所在线程组的名字
System.out.println(Thread.currentThread().getThreadGroup().getName());
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
Thread[] threads = new Thread[Thread.activeCount()];
//把此线程组及其子组中的所有活动线程复制到指定数组中
threadGroup.enumerate(threads);
System.out.println("------------------------------------------------");
for (int i = 0; i < threads.length; i++) {
Thread thread = threads[i];
System.out.println(thread.getName());
}
而最后一个参数stackSize又是代表着什么呢?
Thread( Runnable target,Runnable target,String name,long stackSize)
这个参数代表该线程占用的stack的大小,如果未指定,则该参数默认为0,则由Thread中的JNI(本地方法)设置默认分配虚拟栈大小。