我们知道,在多线程中
Thread thread = new Thread(runnable);
thread.start();以及 thread.run();都可以执行runnable中run方法下的代码,但是二者又有所不同
下面给出一段代码用以体现二者的区别:
以下代码中,通过thread.start()启动线程,最终产生了线程阻塞
package com.xuecheng;
/**
* @author Zonda
* @version 1.0
* @description TODO
* @2024/6/15 16:23
*/
public class ThreadLocal {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
synchronized (this){
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("打了一发");
}
}
}
};
Thread thread = new Thread(runnable);
thread.start();
Thread thread2 = new Thread(runnable);
thread2.start();
}
}
但如果是调用run方法区启动就不会,这是为什么呢?
Thread thread = new Thread(runnable);
thread.run();
Thread thread2 = new Thread(runnable);
thread2.run();
因为当我们直接调用run方法执行的时候,这是直接在main方法的主线程中调用run方法,并没有开启一个新的线程,因此 thread.run();和 thread2.run();会在main方法的主线程中顺序执行。这样就不会出现两个线程去争抢同一个锁中的资源的情况。
而执行start方法会在main线程中异步地开启一个新线程去执行run方法中的代码,如果有两个线程执行start方法,就会出现两个线程同时去执行run方法中的情况。如果一个其中一个线程休眠的时候另一个线程访问这个方法还好,可以交替访问;但是一旦出现一个线程在执行run方法的时候,另一个线程也同时要执行run方法,但是synchronized关键字中的元素只能被一个线程访问,最终会卡死。
我们通过阅读源码也可以看出只有在调用start方法的时候才会创建线程:
start0();
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;//start0();执行成功,走到这里说明线程创建成功
} 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();