Java创建线程有两种方式:(这也是Java面试常被问到一个Java线程基础问题,不往下看你能回答出来吗?)
1) 通过继承 java.lang.Thread 类
2) 通过实现 java.lang.Runnable 接口。
Java启动线程通过调用java.lang.Thread的start()方法,而Thread实现了Runnable接口:
public class Thread implements Runnable
在方法内部调用了Runnable的run()方法来在单独的线程里执行run()方法:
@Override
public void run() {
if (target != null) {
target.run();
}
}
现在问题来了,启动线程为什么不能直接调用run()方法而是调用start()方法呢?
既然start()方法无论如何也会调用run()方法,那么我们直接调用run()方法应该与调用start()方法具有相同的效果吧?错!!
好吧,这也算是一个棘手的多线程问题,在Java面试中经常出现,实际上这个问题并不像看起来那么简单,特别是当你的Java多线程知识只是半桶水,那么你一定会在这个问题上栽跟头。
直接调用run()方法时,run()方法中的代码将在调用run方法的同一个线程中执行,JVM此时并不会创建一个新的线程,也就是说,程序只有主线程一个线程,不会有新的线程被创建,等待run()方法中的代码执行完了,才会顺序执行后面的代码。
当调用Thread.start()方法,JVM将会创建一个新的线程来执行run()方法里的代码,因此调用start()方法才会创建新的线程,在新线程执行run()方法里的代码的同时,后面的代码继续由主线程执行。
start()和run()方法之间的另一个关键区别,就是可以调用run()方法n多次,JVM不会抛出任务错误,但是不能在同一个线程实例里重复调用start()方法。
在同一个线程实例第一次调用start()方法,JVM会创建一个新的线程,但是第二次JVM会抛出java.lang.IllegalThreadStateException异常,因为这个线程已经存在,你不能再创建第二次,你可以中断这个线程,一旦它死了就会消失。
实际上,public void run()方法是在Runnable接口中定义的,并且由于java.lang.Thread类实现了Runnable接口,因此它会自动获取run方法。
接下来我们用代码来演示调用start()方法和调用run()方法的区别。
public class Thread1 extends Thread {
public static void main(String args[]) {
Thread t = new Thread() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is executed the run() method");
}
};
System.out.println(Thread.currentThread().getName() + " Calling the start() method of Thread");
//调用start方法
t.start();
// 等待线程执行完
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " Calling the run() method of Thread");
//调用run方法
t.run();
}
}
执行结果:
main Calling the start() method of Thread
Thread-0 is executed the run() method
main Calling the run() method of Thread
main is executed the run() method
从代码执行的输出结果,配合下面的idea截图左下角的Debugger,可以清晰的看到main/主线程(在Java中执行main()方法的线程)调用start()方法,然后就创建了一个新的名称为Thread-0 的线程,并且run()方法也由该线程执行。但是如果我们直接调用run()方法,并没有创建新的线程来执行,而是由main/主线程来执行。
以上就是Java中的start()和run()方法之间的区别。 只要记住,在start()方法内部调用了run()方法,主要目的是创建一个新线程。 如果直接调用run()方法,则不会创建新线程,而是将在同一线程上执行run()。 这意味着你应该始终通过调用Java中的Thread.start()方法来启动线程。