
代码演示:
/**
* <p>
* start() 和 run() 的比较
* </p>
*
* @author 踏雪彡寻梅
* @version 1.0
* @date 2020/9/20 - 16:15
* @since JDK1.8
*/public class StartAndRunMethod { public static void main(String[] args) { // run 方法演示
// 输出: name: main
// 说明由主线程去执行的, 不符合新建一个线程的本意
Runnable runnable = () -> {
System.out.println("name: " + Thread.currentThread().getName());
};
runnable.run(); // start 方法演示
// 输出: name: Thread-0
// 说明新建了一个线程, 符合本意
new Thread(runnable).start();
}
}复制代码从以上示例可以分析出以下两点:
直接使用 run 方法不会启动一个新线程。(错误方式)
start 方法会启动一个新线程。(正确方式)
start 方法可以启动一个新线程。
立即学习“Java免费学习笔记(深入)”;
start 方法之后, 当前线程(通常是主线程)会请求 JVM 虚拟机如果有空闲的话来启动一下这边的这个新线程。start 方法,也不一定能够立刻的启动线程。srtart 方法调用之后,并不意味这个方法已经开始运行了。它可能稍后才会运行,也很有可能很长时间都不会运行,比如说遇到了饥饿的情况。start 方法,而线程 2 后调用了 start 方法,却发现线程 2 先执行线程 1 后执行的情况。start 方法的顺序并不能决定真正线程执行的顺序。start 方法会牵扯到两个线程。start 方法,第二个才是新的线程。start 就已经是子线程去执行了,这个语句其实是主线程或者说是父线程来执行的,被执行之后才去创建新线程。start 方法创建新线程的准备工作
run 方法中的代码。需要注意: 不能重复的执行 start 方法
代码示例
/**
* <p>
* 演示不能重复的执行 start 方法(两次及以上), 否则会报错
* </p>
*
* @author 踏雪彡寻梅
* @version 1.0
* @date 2020/9/20 - 16:47
* @since JDK1.8
*/public class CantStartTwice { public static void main(String[] args) {
Runnable runnable = () -> {
System.out.println("name: " + Thread.currentThread().getName());
};
Thread thread = new Thread(runnable); // 输出: name: Thread-0
thread.start(); // 输出: 抛出 java.lang.IllegalThreadStateException
// 即非法线程状态异常(线程状态不符合规定)
thread.start();
}
}复制代码报错的原因
start 一旦开始执行,线程状态就从最开始的 New 状态进入到后续的状态,比如说 Runnable,然后一旦线程执行完毕,线程就会变成终止状态,而终止状态永远不可能再返回回去,所以会抛出以上异常,也就是说不能回到初始状态了。这里描述的还不够清晰,让我们来看看源码能了解的更透彻。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 方法
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 */
}
}
}复制代码第一步:启动新线程时会首先检查线程状态是否为初始状态, 这也是以上抛出异常的原因。即以下代码:
if (threadStatus != 0) throw new IllegalThreadStateException();复制代码
其中 threadStatus 这个变量的注释如下,也就是说 Java 的线程状态最初始(还没有启动)的时候表示为 0:
/* Java thread status for tools, * initialized to indicate thread 'not yet started' */private volatile int threadStatus = 0;复制代码
第二步:将其加入线程组。即以下代码:
group.add(this);复制代码
第三步:最后调用 start0() 这个 native 方法(native 代表它的代码不是由 Java 实现的,而是由 C/C++ 实现的,具体实现可以在 JDK 里面看到,了解即可), 即以下代码:
boolean started = false;try { // 第三步, 调用 start0 方法
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 */
}
}复制代码@Overridepublic void run() { // 传入了 target 对象(即 Runnable 接口的实现), 执行传入的 target 对象的 run 方法
if (target != null) {
target.run();
}
}复制代码第一种: 重写了 Thread 类的 run 方法,Thread 的 run 方法会失效, 将会执行重写的 run 方法。
第二种: 传入了 target 对象(即 Runnable 接口的实现),执行 Thread 的原有 run 方法然后接着执行 target 对象的 run 方法。
总结:
run 方法就是一个普通的方法, 上文中直接去执行 run 方法也就是相当于我们执行自己写的普通方法一样,所以它的执行线程就是我们的主线程。run 方法,而是要调用 start 方法,其中可以间接的调用 run 方法。相关学习推荐:java基础
以上就是细品 Java 中启动线程的正确和错误方式的详细内容,更多请关注php中文网其它相关文章!
java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号