从Thread.start()方法看Thread源码,多次start一个线程会怎么样
这篇文章作为Thread类源码剖析的补充,从一个侧面来看Thread源码。也解答了面试高频问题:“多次start一个线程会怎么样?”
答案是:java.lang.IllegalThreadStateException 线程状态非法异常 继承关系是:--->extends IllegalArgumentException--->extends RuntimeException一个运行时异常,下面我们从源码来透彻分析一下start()时做了什么。
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>线程被执行,JVM调用run方法
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* <code>start</code> method) and the other thread (which executes its
* <code>run</code> method).
* <p>
* It is never legal to start a thread more than once.多次调用start方法启动一个线程是非法的
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException if the thread was already已经启动的线程再次start,异常
* started.
* @see #run()
* @see #stop()
*/
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)//状态校验 0:NEW 新建状态
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();//调用native方法执行线程run方法
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();
greop.add(this),把当前线程添加进线程组,源码如下:
/**
* Adds the specified thread to this thread group.
*
* <p> Note: This method is called from both library code
* and the Virtual Machine. It is called from VM to add
* certain system threads to the system thread group.
*
* @param t
* the Thread to be added
*
* @throws IllegalThreadStateException
* if the Thread group has been destroyed
*/
void add(Thread t) {
synchronized (this) {
if (destroyed) {//线程组状态校验
throw new IllegalThreadStateException();
}
if (threads == null) {
threads = new Thread[4];//初始化长度为4的Thread数组
} else if (nthreads == threads.length) {//数组满了就扩容2倍
threads = Arrays.copyOf(threads, nthreads * 2);
}
threads[nthreads] = t;//新线程t添加进数组 // This is done last so it doesn't matter in case the
// thread is killed
nthreads++;//线程数加1 // The thread is now a fully fledged member of the group, even
// though it may, or may not, have been started yet. It will prevent
// the group from being destroyed so the unstarted Threads count is
// decremented.
nUnstartedThreads--;//未启动线程数-1
}
}
启动失败后调用group.threadStartFailed(this),都是加锁方法,从线程组中移除当前线程,源码如下
void threadStartFailed(Thread t) {
synchronized(this) {
remove(t);//移除线程t
nUnstartedThreads++;//未启动线程+1
}
}
private void remove(Thread t) {
synchronized (this) {
if (destroyed) {
return;
}
for (int i = 0 ; i < nthreads ; i++) {
if (threads[i] == t) {
System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
// Zap dangling reference to the dead thread so that
// the garbage collector will collect it.
threads[nthreads] = null;
break;
}
}
}
}
从Thread.start()方法看Thread源码,多次start一个线程会怎么样的更多相关文章
- 一点一点看JDK源码(五)java.util.ArrayList 后篇之Spliterator多线程遍历
一点一点看JDK源码(五)java.util.ArrayList 后篇之Spliterator多线程遍历 liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看J ...
- java 集合与数组的互转方法,与源码分析
前言 java数组与集合需要互相转换的场景非常多,但是运用不好还是容易抛出UnSupportedOperationException.下面讲解一下互转的方法,以及结合源码分异常产生的原因 集合转数组 ...
- Thread.yield()方法表示交出主动权,join表示等待当前线程,可以指定秒数
Thread.yield()方法表示交出主动权,join表示等待当前线程,可以指定秒数 学习了:http://www.importnew.com/14958.html 膜拜一下 源码膜拜: Threa ...
- Java线程状态、线程start方法源码、多线程、Java线程池、如何停止一个线程
下面将依次介绍: 1. 线程状态.Java线程状态和线程池状态 2. start方法源码 3. 什么是线程池? 4. 线程池的工作原理和使用线程池的好处 5. ThreadPoolExecutor中的 ...
- 【实习记】2014-08-15文档太少看着源码用cgicc+stl库之模板谓词函数对象
总结1: 今天找到了昨天scanf的问题答案,scanf与printf一样的神奇而复杂,稍不留神,就会被坑.scanf函数在读入非空白符分割的多个字符串的解决方法是这个:/* 以 | 分割 * ...
- 读取xml文件转成List<T>对象的两种方法(附源码)
读取xml文件转成List<T>对象的两种方法(附源码) 读取xml文件,是项目中经常要用到的,所以就总结一下,最近项目中用到的读取xml文件并且转成List<T>对象的方法, ...
- 一点一点看JDK源码(〇)
一点一点看JDK源码(〇) liuyuhang原创,未经允许进制转载 写在前面: 几乎所有的大神都会强调看源码,也强调源码的重要性: 但是如何看源码,源码看什么?看了什么用?看了怎么用? 困扰很多人, ...
- 一点一点看JDK源码(一)Collection体系概览
一点一点看JDK源码(一)Collection体系概览 liuyuhang原创,未经允许进制转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 Collection为集 ...
- 一点一点看JDK源码(二)java.util.List
一点一点看JDK源码(二)java.util.List liuyuhang原创,未经允许进制转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 List译为表,一览表, ...
随机推荐
- shell之 printf 输出语句
总结: (1)printf 使用引用文本或空格分隔的参数,外面可以在printf中使用格式化字符串,还可以制定字符串的宽度.左右对齐方式等.默认printf不会像 echo 自动添加换行符,我们可以手 ...
- python的计数引用分析(一)
python的垃圾回收采用的是引用计数机制为主和分代回收机制为辅的结合机制,当对象的引用计数变为0时,对象将被销毁,除了解释器默认创建的对象外.(默认对象的引用计数永远不会变成0) 所有的计数引用+1 ...
- 再起航,我的学习笔记之JavaScript设计模式16(享元模式)
### 享元模式 **享元模式(Flyweight):** 运用共享技术有效地支持大量的细粒度的对象,避免对象间拥有相同内容造成多余的开销. 上回我们在组合模式中创建了文章列表类,这次我们要向不同的文 ...
- exjs上传图片异常:com.jspsmart.upload.SmartUploadException: File can't be saved (1120).
错误: 文件名格式不对:未命??.jpg SmartUpload mySmartUpload = new SmartUpload(); com.jspsmart.upload.File myFile ...
- Akka(23): Stream:自定义流构件功能-Custom defined stream processing stages
从总体上看:akka-stream是由数据源头Source,流通节点Flow和数据流终点Sink三个框架性的流构件(stream components)组成的.这其中:Source和Sink是stre ...
- git 介绍及其使用总结
版本控制 Git 目录 目录 2 第1章 Shell和vi 4 1.1 什么是shell 4 1.2 shell分类 4 1.3 认识bash这个shell ...
- [转载]python 详解re模块
原文地址:python 详解re模块作者:Rocky 正则表达式的元字符有. ^ $ * ? { [ ] | ( ) .表示任意字符 []用来匹配一个指定的字符类别,所谓的字符类别就是你想匹配的一个字 ...
- 201521123107 《Java程序设计》第6周学习总结
第6周作业-接口.内部类与Swing 1.本周学习总结 2.书面作业 1.clone方法 1.1 Object对象中的clone方法是被protected修饰,在自定义的类中覆盖clone方法时需要注 ...
- 团队作业9——测试与发布(Beta版本)
Beta版本测试报告 一bug汇总 计时没有显示即倒计时,难度不同的功能没有实现(已修复) 没有导入试卷和错题功能(不打算修复) 前台管理功能(部分修复) 界面美观问题(没有修复也不打算修复) 二.场 ...
- 扫雷游戏制作过程(C#描述):第二节、界面设计
前言 这里给出教程原文地址. 该项目已经放在github上托管. 扫雷界面设计 界面的设计,首先需要创建一个菜单栏.具体方法在左边找到工具箱窗口,展开其中的菜单和工具栏,找到MenuStrip选项,双 ...