对Thread的start()和run()的一些认识

  • Post author:
  • Post category:其他


查漏补缺,巩固基础。

通常我们

需要新建线程执行操作时,可以这么写:


写法一:

在需要的地方调用new MyThread().start(),并重写匿名Thread类的run方法,如下;

		new Thread() {
			@Override
			public void run() {
				System.out.println("Thread run");
			}
		}.start();

输出:Thread run


写法二:

实现Runnable接口(实现Runnable的run()方法),然后传入Thread的构造方法中,再调用Thread的start()方法,如下:

		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("Runnable run");
			}
		}).start();

输出: Runnable run

注意,

写法一是重写了Thread的run()方法,而写法二是实现了Runnable接口的run()方法。

那么问题来了:



如果我同时重写Thread和实现Runnable两个run()方法,像下面这样,会怎么样呢?
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("Runnable run");
			}
		} ) {
			@Override
			public void run() {
				System.out.println("Thread run");
			}
		}.start();

实际运行输出:

Thread run

为什么Runnable的run方法就没有得到执行了呢?这个就得知道Thread的start()方法运行之后,发生了什么。

如果去看Thread类的start()方法源码,我们会发现它会调用一个native方法start0(),这个方法就不做探究了,它会在底层开启异步线程,并调用此Thread的run()方法。

那么Thread的run()方法,源码里又是怎么实现的呢?贴出来看下:

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

很简单,直接调用了target对象的run()方法。那么target是什么呢?它正是Thread的构造方法传入的Runnable对象。见Thread的构造方法的源码:

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

那么现在捋一下,为什么我们同时重写了Thread的run(),和实现了Runnable接口的run()之后,只有Thread的run()得到运行了?

因为原本Thread的run()所做的唯一的事就是调用Runnable对象的run(),而上面我们把Thread的run()给重写了,那自然Runnable对象的run()就得不到执行了。

那有没有办法让这两个run()都得到执行呢?很简单,只要在匿名Thread的run()方法里加一行super.run()即可,因为super就是Thread类。像下面这样;

		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("Runnable run");
			}
		} ) {
			@Override
			public void run() {
				super.run(); //添加这一行
				System.out.println("Thread run");
			}
		}.start();

输出结果;

Runnable run
Thread run

另外,如果不用匿名内部类,而是新建了MyThread类继承Thread类,然后使用的时候又想传入Runnable对象的话,那必须给MyThread类重写一个带Runnable类型参数的构造方法,然后在构造方法中调用super(runnable),因为Java中构造方法是不会被继承的。

还有一点:

直接调用Thread对象的run()方法,或者直接调用Runnable对象的run()方法,可以开启新线程吗?


答案是

不行

。这样的调用,是在当前线程运行run()方法,就跟调用普通方法没什么区别,而start()是会开启新线程的。



版权声明:本文为fenggering原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。