同一个线程多次调用start()会出现的问题
结果:
线程首先会运行一次,然后抛出java.lang.IllegalThreadStateException异常。

根据控制台的异常信息,定位到Thread.java的第708行,也就start()方法内部,打个断点调试:

调试发现,第一个次运行start()方法时,threadStatus是0,此时if条件不满足,继续执行,会将当前线程添加到线程组中去执行。
第二次运行start()方法时,threadStatus变成了2,if条件满足,于是抛出了java.lang.IllegalThreadStateException异常。
start()方法的源码:
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
让这个线程开始执行。JVM会调用这个线程的run()方法。
* <p>
* 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
* started.
如果该线程已经启动,则再次调用start()方法,就会抛出IllegalThreadStateException异常。
* @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)//新的线程threadState值是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);//通知线程组该线程将要开始运行,这样该线程就会被添加到线程列表中,此时列表的unstarted数将会减少。 boolean started = false;
try {
start0();//调用原生方法态方法启动线程
started = true;//已经运行的标记设置为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 */
}
}
}
group.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) {//如果线程组的销毁标记(destroyed)是true,则抛出IllegalThreadStateException
throw new IllegalThreadStateException();
}
if (threads == null) {//如果线程数组为空,则初始为4个新的线程
threads = new Thread[4];
} else if (nthreads == threads.length) {//如果当前线程组已满,则扩容至原来的2倍
threads = Arrays.copyOf(threads, nthreads * 2);
}
threads[nthreads] = 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
}
}
threadStartFailed()源码分析:
/**
* Notifies the group that the thread {@code t} has failed
* an attempt to start.
* 通知线程组该线程尝试运行失败
* <p> The state of this thread group is rolled back as if the
* attempt to start the thread has never occurred. The thread is again
* considered an unstarted member of the thread group, and a subsequent
* attempt to start the thread is permitted.
*
* @param t
* the Thread whose start method was invoked
*/
void threadStartFailed(Thread t) {
synchronized(this) {//同步
remove(t);//从线程组中移除该线程
nUnstartedThreads++;//未启动线程数+1
}
}
结论:
同一个线程只能调用start()方法一次,多次调用会抛出java.lang.IllegalThreadStateException。启动一个线程,需要调用start()方法而不是run()方法。此时,当前线程会被添加到线程组中,进入就绪状态,等待线程调度器的调用,若获取到了资源,则能进入运行状态,run()方法只是线程体,即线程执行的内容,若没调用start()方法,run()方法只是一个普通的方法。
同一个线程多次调用start()会出现的问题的更多相关文章
- c/c++ 多线程 多个线程等待同一个线程的一次性事件
多线程 多个线程等待一个线程的一次性事件 背景:从多个线程访问同一个std::future,也就是多个线程都在等待同一个线程的结果,这时怎么处理. 办法:由于std::future只能被调用一次get ...
- Android jni c/c++线程通过CallVoidMethod调用java函数出现奔溃问题
最近在移植网络摄像机里的p2p库到android平台,需要用到jni,最近在c线程了调用java函数的时候 出现一个问题,假如在同一个线程调用java函数是没问题的,但在一个c线程了调用java函数就 ...
- 判断是否在同一个线程-GetCurrentThreadId()用法
线程 在一个程序中,这些独立运行的程序片断叫作"线程"(Thread),利用它编程的概念就叫作"多线程处理".利用线程,用户可按下一个按钮,然后程序会立即作出响 ...
- 解析Qt元对象系统(五) Q_INVOKABLE与invokeMethod(automatic connection从Qt4.8开始的解释已经与之前不同,发送对象驻足于哪一个线程并不重要,起到决定作用的是接收者对象所驻足的线程以及发射信号(该信号与接受者连接)的线程是不是在同一个线程)good
概述查看Qt源码可知,Q_INVOKABLE是个空宏,目的在于让moc识别. 使用Q_INVOKABLE来修饰成员函数,目的在于被修饰的成员函数能够被元对象系统所唤起. Q_INVOKABLE与QMe ...
- https://github.com/python/cpython/blob/master/Doc/library/contextlib.rst 被同一个线程多次获取的同步基元组件
# -*- coding: utf-8 -*- import time from threading import Lock, RLock from datetime import datetime ...
- BeginInvoke 方法真的是新开一个线程进行异步调用吗?
转自原文BeginInvoke 方法真的是新开一个线程进行异步调用吗? BeginInvoke 方法真的是新开一个线程进行异步调用吗? 参考以下代码: public delegate void tre ...
- Java创建线程后,调用start()方法和run()的区别
1) start方法: 用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码.通过调用Thread类的start()方法来启动一个线程,这时此 ...
- java future模式 所线程实现异步调用(转载
java future模式 所线程实现异步调用(转载) 在多线程交互的中2,经常有一个线程需要得到另个一线程的计算结果,我们常用的是Future异步模式来加以解决.Future顾名思意,有点像期货市场 ...
- C# 线程池异步调用
许多应用程序使用多个线程,但这些线程经常在休眠状态中耗费大量的时间来等待事件发生.其他线程可能进入休眠状态,并且仅定期被唤醒以轮询更改或更新状态信息,然后再次进入休眠状态.为了简化对这些线程的管理,. ...
随机推荐
- DBCC维护语句语法
一.DBCC维护语句:对数据库.索引或文件组进行维护的任务--1.DBCC CLEANTABLE,回收删除的可变长度列和文本列的空间 DBCC CLEANTABLE ( { 'database_na ...
- ubuntu 下 rvm 卸载和重装
卸载: sudo apt-get --purge remove ruby-rvm sudo rm -rf /usr/share/ruby-rvm /etc/rvmrc /etc/profile.d/r ...
- JAVA&PYTHON
- 模块移除 命令rmmod 的实现
// rmmod.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include < ...
- soft selective sweeps 下的群体进化
1.Hard and soft selective sweeps 长期以来,快速适应主要与选择作用于高度多基因的数量性状有关,例如在育种试验期间.这些性状可以通过对大量已经存在的多态性的群体频率的微小 ...
- spring boot 2 内嵌Tomcat Stopping service [Tomcat]
我在使用springboot时,当代码有问题时,发现控制台打印下面信息: Connected to the target VM, address: '127.0.0.1:42091', transpo ...
- 问题:使用ajax跳转到新页面无效(浏览器Safari)
问题:使用ajax跳转到新页面无效(浏览器Safari) window.open("{% url "runtestinfo" %}") 但是使用loca ...
- 简单的jQ代码
简单的jQ代码 /* * Lazy Load - jQuery plugin for lazy loading images * * Copyright (c) 2007-2012 Mika Tuup ...
- NumPy IO
NumPy IO Numpy 可以读写磁盘上的文本数据或二进制数据. NumPy 为 ndarray 对象引入了一个简单的文件格式:npy. npy 文件用于存储重建 ndarray 所需的数据.图形 ...
- Android 实现简单 倒计时60秒,一次1秒
倒计时功能如上图所示,其实就几行代码即可实现效果啦!!! /** 倒计时60秒,一次1秒 */ CountDownTimer timer = new CountDownTimer(60*1000, 1 ...