关于Thread的构造在JDK文档中如下:

之后会把上面所有的构造都会学习到,这次主要是去研究一下图上标红的默认构造,当然大家肯定对于它都有些不屑,这有啥可学的,不new一个然后start线程不就启动了,属于线程最最基础的东东,然后它的背后并非我们都知道,所以下面开始学习。

Thread常规知识:

先来看一下默认构造的源码:

先了解一下默认线程名的起名规则,看下nextThreadNum():

原来是有一个静态计数的变量,那也就是说默认new出来的线程是以"Thread-0、Thead-1"这样的规则来命名的,用代码来验证下:

编译运行:

果真如预期,但是目前线程中并未做任何事情,而我们知道可以给线程构造中传一个Runnable接口:

那在默认构造Thread的时候有没有一个空的Runnable去执行呢?看源码【贴出关键代码】:

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

从代码中可以看到并未自动创建一个Runnable,而是直接传的null,那最终在init()中是如何搞的呢?

private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
if (name == null) {
throw new NullPointerException("name cannot be null");
} this.name = name.toCharArray(); 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 (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();
}

只看核心代码,可以看到将Thread的成员变量target赋值为null了,

那此时我们执行创建的线程会调用start()方法,那接着看下它:

public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException(); /* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this); boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
} private native void start0();

最终转到C层去执行线程的启动了,而底层的代码暂且不深纠了,这里要知道C层会去调用Thread的run()方法,所以转到run方法去看一眼:

但是!!!可以重写它的run方法来执行我们的动作,如下:

编译运行:

那接着修改代码:

接着在创建runnable的时候也手动给它取个名字,如下:

这样关于Thread的构造就学习了四种了,当然也是最经常使用的,比较简单:

ThreadGroup的概念及守护线程初探:

关于这个内容可能就不是太清楚啦,可以看一下剩下线程构造函数中:

全是跟ThreadGroup相关,貌似实际工作中完全木有接触过它,所以说首先得了解它,从哪了解呢,直接从源码:

public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
} private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
if (name == null) {
throw new NullPointerException("name cannot be null");
} this.name = name.toCharArray(); 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 (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();
}

从源码中可以看到,默认无参的构造函数并未指定ThreadGroup,当在执行init()方法时发现没有ThreadGroup,则会获得父线程的ThreadGroup,而父线程可以通过currentThread()方法获取,而我们在之前【http://www.cnblogs.com/webor2006/p/7682063.html】有介绍过,对于创建一个线程实际是有两个线程,其中有一个就是main线程,也就是用来启动我们自己创建的线程的,那是不是我们线程的parent就是main呢?下面来做实验论证:

那如果此时新建一个线程,然后再看一下它的ThreadGroup,如下:

那说明创建线程时未指定ThreadGroup,那会以父线程的ThreadGroup作为该线程的ThreadGroup,刚好跟源码逻辑吻和,那是不是说子线程将和父线程在同一个ThreadGroup中?也就是说目前ThreadGroup中应该包含了2个线程,那我们打印看一下:

编译运行:

这是在MAC上的表现,但是!!!如果在windows平台其输出并非如我们所预期的,下面在windows下运行看一下结果:

总结:

  • 创建线程对象Thread,默认有一个线程名,以Thread-开头,从0开始计数:Thread-0、Thread-1、Thread-2等。
  • 如果在构造Thread()的时候没有传递Runnable或者没有复写Thread的run方法,该Thread将不会调用任何东西;如果传递了Runnable接口的实例,或者复写的Thread的run方法,则会执行该方法的逻辑单元(逻辑代码)。
  • 如果构造线程对象时未传入ThreadGroup,Thread会默认获取父线程的TreadGroup作为该线程的ThreadGroup,此时子线程将和父线程在同一个ThreadGroup中。

java线程基础巩固---构造Thread对象你也许不知道的几件事的更多相关文章

  1. 4.构造Thread对象你也许不知道的几件事

    1.Thread类对象只有在调用了start()方法之后,JVM虚拟机才会给我们创建一个真正的线程!否则就不能说是创建了线程!也就是说new Thread()之后,此时实际上在计算机底层,操作系统实际 ...

  2. (转)关于 Java 对象序列化您不知道的 5 件事

    关于 Java 对象序列化您不知道的 5 件事 转自:http://developer.51cto.com/art/201506/479979.htm 数年前,当和一个软件团队一起用 Java 语言编 ...

  3. 关于 Java 对象序列化您不知道的 5 件事

    数年前,当和一个软件团队一起用 Java 语言编写一个应用程序时,我体会到比一般程序员多知道一点关于 Java 对象序列化的知识所带来的好处. 关于本系列 您觉得自己懂 Java 编程?事实上,大多数 ...

  4. 关于 java.util.concurrent 您不知道的 5 件事--转

    第 1 部分 http://www.ibm.com/developerworks/cn/java/j-5things4.html Concurrent Collections 是 Java™ 5 的巨 ...

  5. 关于 Java Collections API 您不知道的 5 件事,第 1 部分

    定制和扩展 Java Collections Java™ Collections API 远不止是数组的替代品,虽然一开始这样用也不错.Ted Neward 提供了关于用 Collections 做更 ...

  6. 关于 Java Collections API 您不知道的 5 件事--转

    第 1 部分 http://www.ibm.com/developerworks/cn/java/j-5things2.html 对于很多 Java 开发人员来说,Java Collections A ...

  7. 关于 Java 性能监控您不知道的 5 件事,第 1 部分

    责怪糟糕的代码(或不良代码对象)并不能帮助您发现瓶颈,提高 Java? 应用程序速度,猜测也不能帮您解决.Ted Neward 引导您关注 Java 性能监控工具,从5 个技巧开始,使用Java 5 ...

  8. java线程基础巩固---分析Thread的join方法详细介绍,结合一个典型案例

    关于Thread中的join方法貌似在实际多线程编程当中没怎么用过,在当初学j2se的时候倒时去学习过它的用法,不过现在早已经忘得差不多啦,所以对它再复习复习下. 首先先观察下JDK对它的介绍: 其实 ...

  9. 关于Java Collections API您不知道的5件事,第2部分

    注意可变对象 java.util 中的 Collections 类旨在通过取代数组提高 Java 性能.如您在 第 1 部分 中了解到的,它们也是多变的,能够以各种方 式定制和扩展,帮助实现优质.简洁 ...

随机推荐

  1. loadrunner脚本因为没有token报错

    目录 场景 解决过程 解决方案 总结 场景 用loadrunner11录制脚本,处理后回放,加上检查点,报错找不到检查点对应的内容,去掉检查点,没有报错,但是打开页面没有该操作的痕迹.手动在页面上操作 ...

  2. Centos7搭建主从DNS服务器

    1.准备 例:两台192.168.11.10(主),192.168.11.11(从),域名www.test1.com # 主从DNS服务器均需要安装bind.bind-chroot.bind-util ...

  3. Mac下使用sshpass让iterm2支持多ssh登录信息保存

    mac下没有xshell等连接linux服务器的工具,当需要管理的服务器越来越多之后,密码管理就成了一个很头疼的问题,每次都需要去复制粘贴密码,浪费了很多时间,在网上查了不少资料,发现mac下可以使用 ...

  4. vue $refs获取dom元素

    1.今天做vue项目有个获取dom节点,主要目的是获取节点让滚动到顶部 首先在滑动容器去添加ref <div class="contentScroll" ref=" ...

  5. 学习笔记:html学习之一:html基本标记

    1. 概论 一个完整的 HTML 文档必须包含 3 个部分: 一个由 元素定义的文档版本信息. 一个由 定义各项声明的文档头部, 作为各种声明信息的包含元素出现在文档的顶端,并且要先于 出现. 一个由 ...

  6. 2019牛客暑期多校训练营(第六场)-D Move

    题目链接:https://ac.nowcoder.com/acm/contest/886/D 题意:给n个物品,每个物品有一个体积值,K个箱子,问箱子的最小体积为多少可将物品全部装下. 思路:比赛时一 ...

  7. linux各种IPC机制

    docker中的资源隔离,一种就是IPC的隔离.IPC是进程间通信. 下面的文章转载自https://blog.csdn.net/yyq_9623/article/details/78794775 原 ...

  8. *【Python】【demo实验31】【练习实例】【使用turtle画小猪佩奇】

    如下图小猪佩奇: 要求使用turtle画小猪佩奇: 源码: # encoding=utf-8 # -*- coding: UTF-8 -*- # 使用turtle画小猪佩奇 from turtle i ...

  9. yum方式安装mono

    https://blog.csdn.net/qq_21153619/article/details/81459359 这样应该比较简单 yum方式按照mono rpm --import "h ...

  10. oracle——学习之路(oracle内置函数)

    oracle与很多内置函数,主要分为单行函数与集合函数. 首先要提一下dual表,它oracle的一个表,没有什么实质的东西,不能删除它,否则会造成Oracle无法启动等问题,他有很大用处,可以利用它 ...