首先来看一张jdk-api中对于start 和 run 的描述.
下面我们简单看一下代码:
- // 继承Thread类 重写run()
- class MyThread extends Thread {
- @Override
- public void run() {
- while (true) {
- System.out.println("thread");
- try {
- sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- public class Demo1 {
- public static void main(String[] args) {
- MyThread thread = new MyThread();
- thread.start();
-
- while (true) {
- System.out.println("main");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- // 通过重写Runnable 来实现创建线程
- class MyRunnable implements Runnable {
- @Override
- public void run() {
- while (true) {
- System.out.println("thread");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- public class Demo2 {
- public static void main(String[] args) {
- MyRunnable runnable = new MyRunnable();
- Thread thread = new Thread();
- thread.start();
-
-
- while (true) {
- System.out.println("main");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- }
- }
通过上述代码, 我们可以看出, 无论哪一种方法创建线程, 我们都需要重写run(), 而API中对于run() 的介绍,如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。Thread 的子类应该重写该方法。run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
我们确定一件事, start() 才是真正启动线程的方法, 真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。
通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行, 然后通过此Thread类调用方法run()来完成其运行操作的, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。 一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止
图一, 继承Thread类打印效果
这个时候创建了新的线程, 打印了 thread
然后, 操作系统, 调度线程的时候, 是一个 "随机" 的过程
执行 sleep, 线程就进入阻塞.
sleep 时间一到, 线程就恢复就绪状态, 参与线程调度.
当两个线程都参与调度的时候, 不确定谁先谁后
图二, 重写Runnable接口
这个时候只是打印了 main , 并没有创建新的线程
实现Runnable接口,创建Thread时,会调用
- public Thread(Runnable target) {
- init(null, target, "Thread-" + nextThreadNum(), 0);
- }
-
- private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
- init(g, target, name, stackSize, null, true);
- }
-
把Runnable的实现类赋值给target,当使用run方法时```java会调用我们实现时写的run()方法. 因此,run方法只是调用了一个普通方法,并没有启动另一个线程,程序还是会按照顺序执行相应的代码, 因此,无论使用哪种方式创建线程, run方法都是用来处理线程对应的业务逻辑.