Thread(target)之run()方法

2021年9月30日 7点热度 0条评论 来源: 理想二旬

不论是继承Tread类创建线程还是实现Runnable接口创建线程,启动线程一般都是调用Thread类的start()方法,然后由虚拟机自动调用Thread类的run()方法,调用过程如下:

1.首先打开start()方法:

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;
        } 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 */
            }
        }
    }

start()方法调用了start0()方法,继续:

 private native void start0();

start0()方法为native,网上搜索可得 JVM自动调用了run()方法,代码被封装了。

然后run()方法如下:

 public void run() {
        if (target != null) {
            target.run();
        }
    }

自此,调用线程的过程分析完毕。

接下来看以下代码:

1.

public class ThreadDemo {

	public static void main(String[] args) {

		Thread thread = new Thread();
		thread.start();
	}

}

只是调用了最普通的线程类,没有任何打印输出。分析以上调用线程过程:

thread.start()调用后,会调用start0()方法,然后调用run()方法,由于该线程(thread)没有实现Thread类,只是最普通的线程类,所以也没有重写run()方法,所以只能调用JDK定义的Thread的run()方法,即:

public void run() {
        if (target != null) {
            target.run();
        }
    }

target为空,所以该run()方法什么也没有实现,所以没有任何输出(假定运行结果都是在控制台打印字符串)。

2.

public class ThreadDemo extends Thread {

    public void run(){
        System.out.println("自定义线程被调用");
    }

    public static void main(String[] args) {
        ThreadDemo thread = new ThreadDemo();
        thread.start();
    }
}


该线程thread继承Thread类,并重写了run()方法,运行结果如下:

自定义线程被调用


由1情况分析可知:重写了run()方法,所以优先调用该run()方法


3.

public class ThreadDemo {


	public static void main(String[] args) {


		new Thread(new Runnable() {


			@Override
			public void run() {
				System.out.println("执行的run()方法为Runnable接口实现");


			}


		}) .start();


	}


}

该情况实现Runnable接口并且重写了run()方法,运行结果如下:

执行的run()方法为Runnable接口实现


分析run()方法调用可知:

public void run(){
      if (target != null)
 {            target.run();
        }
  }

此时target不为null,则会调用target.run()方法即我们自己重写的run()方法

4.
public class ThreadDemo {


    public static void main(String[] args) {


        new Thread(new Runnable() {


            @Override
            public void run() {
                System.out.println("执行的run()方法为Runnable接口实现");


            }


        }) {
            public void run() {
                System.out.println("执行的run()方法为Thread类实现");
            }
        }.start();


    }


}

该情况不仅Runnable接口重写了run()方法,而且Thread类也重写了run()方法
运行结果如下:


执行的run()方法为Thread类实现


分析调用过程:在调用run()方法时,如果重写了Thread类的run()方法,则会首先调用Thread类重写的run()方法
5.

public class ThreadDemo {


	public static void main(String[] args) {


		new Thread(new Runnable() {


			@Override
			public void run() {
				System.out.println("执行的run()方法为Runnable接口实现");


			}


		}) {
			public void run() {
				System.out.println("执行的run()方法为Thread类实现");
				super.run();
			}
		}.start();


	}


}


仅仅增添了一句:super.run() 运行结果如下:

执行的run()方法为Thread类实现
执行的run()方法为Runnable接口实现


这个过程就有复杂了,但是还是慢慢分析:
首先调用Thread.start()方法,然后会调用Thread类中重写的run()方法,则输出:执行的run()方法为Thread类实现
然后接着程序继续往下执行调用super.run(),super指超类即JDK定义的最基本的Thread类,然后调用JDK定义的Thread类的run()方法:

public void run() {
        if (target != null) {
            target.run();
        }
    }

此时target不为null,与第一种情况不同!然后会调用target的run()方法,即自己重写的Runnable接口的run()方法,输出为:执行的run()方法为Runnable接口实现

综合上述五种情况分析:
1.如果没有继承Thread类只是创建普通Thread类对象,则线程什么都不做
2.如果继承了Thread类:
    a.如果重写了run()方法:则JVM调用该方法
    b.如果没有重写run()方法:则JVM调用JDK自己定义的run()方法
         I.如果指定了target,则调用target的run()方法
         II.如果没有指定target,则什么都不做。


总结:
对于Thread(Runnable target).start()来说:不管target是否为空,Thread都会首先调用自己的run()方法:如果重写了该方法,且没有super.run(),则永远都不会调用Runnable中实现的run()方法;有super.run()的话,则首先调用完Thread自己的run()方法,然后决定是否再调用target中的run()方法;如果没有重写Thread自己的run()方法,则会判断target是否为空,然后决定是否调用target的run()方法。


析的可能有点乱,但仔细梳理上述几种情况的代码后,就会体会到。如有错误,欢迎指正。

    原文作者:理想二旬
    原文地址: https://blog.csdn.net/inspiredbh/article/details/54974465
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。