java线程基础巩固---构造Thread对象你也许不知道的几件事
关于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对象你也许不知道的几件事的更多相关文章
- 4.构造Thread对象你也许不知道的几件事
1.Thread类对象只有在调用了start()方法之后,JVM虚拟机才会给我们创建一个真正的线程!否则就不能说是创建了线程!也就是说new Thread()之后,此时实际上在计算机底层,操作系统实际 ...
- (转)关于 Java 对象序列化您不知道的 5 件事
关于 Java 对象序列化您不知道的 5 件事 转自:http://developer.51cto.com/art/201506/479979.htm 数年前,当和一个软件团队一起用 Java 语言编 ...
- 关于 Java 对象序列化您不知道的 5 件事
数年前,当和一个软件团队一起用 Java 语言编写一个应用程序时,我体会到比一般程序员多知道一点关于 Java 对象序列化的知识所带来的好处. 关于本系列 您觉得自己懂 Java 编程?事实上,大多数 ...
- 关于 java.util.concurrent 您不知道的 5 件事--转
第 1 部分 http://www.ibm.com/developerworks/cn/java/j-5things4.html Concurrent Collections 是 Java™ 5 的巨 ...
- 关于 Java Collections API 您不知道的 5 件事,第 1 部分
定制和扩展 Java Collections Java™ Collections API 远不止是数组的替代品,虽然一开始这样用也不错.Ted Neward 提供了关于用 Collections 做更 ...
- 关于 Java Collections API 您不知道的 5 件事--转
第 1 部分 http://www.ibm.com/developerworks/cn/java/j-5things2.html 对于很多 Java 开发人员来说,Java Collections A ...
- 关于 Java 性能监控您不知道的 5 件事,第 1 部分
责怪糟糕的代码(或不良代码对象)并不能帮助您发现瓶颈,提高 Java? 应用程序速度,猜测也不能帮您解决.Ted Neward 引导您关注 Java 性能监控工具,从5 个技巧开始,使用Java 5 ...
- java线程基础巩固---分析Thread的join方法详细介绍,结合一个典型案例
关于Thread中的join方法貌似在实际多线程编程当中没怎么用过,在当初学j2se的时候倒时去学习过它的用法,不过现在早已经忘得差不多啦,所以对它再复习复习下. 首先先观察下JDK对它的介绍: 其实 ...
- 关于Java Collections API您不知道的5件事,第2部分
注意可变对象 java.util 中的 Collections 类旨在通过取代数组提高 Java 性能.如您在 第 1 部分 中了解到的,它们也是多变的,能够以各种方 式定制和扩展,帮助实现优质.简洁 ...
随机推荐
- day37 GIL、同步、异步、进程池、线程池、回调函数
1.GIL 定义: GIL:全局解释器锁(Global Interpreter Lock) 全局解释器锁是一种互斥锁,其锁住的代码是全局解释器中的代码 为什么需要全局解释器锁 在我们进行代码编写时,实 ...
- Spring boot + Jpa + Maven + Mysql 初级整合
1.使用Idea创建spring boot工程的博客 https://www.cnblogs.com/black-spike/p/8017768.html 2.本篇博客参考网址 https://blo ...
- 自学电脑游戏第四天(Swing)
继续之前的 3.组合框(JComboBox) 例题:利用JComboBox设计一个选择城市的程序. import java.awt.*; import javax.swing.*; public cl ...
- 2019牛客暑期多校训练营(第八场)-A All-one Matrices (单调栈+前缀和)
题目链接:https://ac.nowcoder.com/acm/contest/888/A 题意:给n×m的01矩阵,求出其中全为1的矩阵个数(不被其它全1矩阵包括). 思路:和第二场多校的次大子矩 ...
- SpringBoot整合MyBatis完成添加用户
怎么创建项目就不说了,可以参考:https://www.cnblogs.com/braveym/p/11321559.html 打开本地的mysql数据库,创建表 CREATE TABLE `user ...
- PTA(Advanced Level)1025.PAT Ranking
To evaluate the performance of our first year CS majored students, we consider their grades of three ...
- Number of Containers ZOJ - 3175(数论题)
Problem Description For two integers m and k, k is said to be a container of m if k is divisible by ...
- PHP数组和对象之间的互换
今天在和前端对接接口的时候,从后台返回数据给前端的时候出现如下JSON格式数据 "goods": [ { "id": "dEQ144800584Lx& ...
- 【求教 探讨】python tkinter的messagebox
最近有一个要求,用python的tkinter制作一个messagebox,传入3个参数: title text timeout.用户可以点击“确定” 关闭窗口: 或者 等待几秒(timeout) ...
- 题解 P2879 【[USACO07JAN]区间统计Tallest Cow】
题目链接: https://www.luogu.org/problemnew/show/P2879 思路: 先不管最大高度,我们读入一对x,y.说明,x+1~y-1之间牛的身高都小于x,y. 然后不妨 ...