多线程的8大基础核心——实现多线程的几种方法

1、实现多线程一共有两种方法(官方文档这么说的)

(1)声明类是Thread的子类(即继承Thread),不推荐使用这种方法

缺点:从代码架构角度去考虑,run()方法就是我们具体执行的内容,run()方法的执行应该与我们线程(Thread)的创建、执行是解耦的,不应该把二者混为一谈。

继承Thread实现线程,这种时候我们每次新建一个任务,只能去创建一个新的线程,而线程的创建、执行、销毁是十分消耗资源的,但是通过实现Runnable接口的方法,我们就可以利用线程池之类的工具,可以大大减小资源的消耗。

Java是不允许双继承的,一旦继承Thread,就无法继承其他的类,是的类的扩展性降低。

public class ThreadStyle extends Thread {
    @Override
    public void run() {
        System.out.println("通过集成Thread类实现多线程");
    }

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

(2)声明一个实现Runnable接口的类,然后实现run()方法(即实现Runnable接口),这个方法相对更好。

public class RunnableStyle implements Runnable {
    @Override
    public void run() {
        System.out.println("通过实现Runnable接口实现多线程");
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new RunnableStyle());
        t1.start();
    }
}

以上两种方法都是执行run(),只不过run()的来源不同,以下是Thread类原本run()方法的代码

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

上面代码中的target就是Runnbale(第二种方法在创建线程的时候,传入的)

用第一种方法实现线程的时候,因为要重写run()方法,所以线程最后执行的方法run()是我们重写的run()方法。

用第二种方法实现线程的时候,因为要执行所传入的Runnable的run()方法,所以线程最后执行的run()方法是我们实现的run()方法。

 

3、同时使用两种实现线程的方式会怎么样

4、网上错误观点

(1)线程池创建线程也算是一种新建线程的方式

错误原因:线程池创建线程的原理也是使用的new Thread()的方式

(2)通过Callable和FutureTask创建线程,也算是一种新建线程的方式

错误原因:

(3)定时器

(4)匿名内部类

(5)Lambda表达式

网上创建线程的方式多种多样,但是其本质只有以上两种创建线程的方式。

5、实现多线程的常见面试问题

问题1:有多少种实现线程的方法

从不同的角度看,会有不同的答案。

1)典型回答:两种;一种是继承Thread类;另一种是实现Runnable接口(这种方式实现更好),但是看原理,这两种方式的本质是一样的,因为run()方法的代码如下,(代码省略),这f两种方法都是基于Thread的run()方法实现的,只不过一种是重写run()方法,一种是通过执行run()方法中的target.run()去实现的。

总结回答:从本质上讲只有一种,都需要新建Thread类,但是通常我们区分为两种方法,一种是继承Thread类,一种是实现Runnable接口,另外还有一些外在形式(代码实现上)上去实现多线程,如线程池、计时器等。

问题2:实现Runnable接口和继承Thread类那种方式更好

1)从代码架构角度:这里其实是分有两件事情的,一就是具体的任务,也就是run()方法要执行的内容;二就是跟线程的生命周期相关的,如创建、运行、销毁线程,而这件事情应该是Thread类应该去做的事情,这两件事情的目的不也一样,从代码架构角度看,应该解耦,所以事先Runnable接口的方法更好点。

2)新建线程的损耗:如果我们使用继承Thread这种方式去实现线程,那么每次我们想要新建启动一个任务,都需要new 一个Thread类,这样损耗比较大,每一次都需要经过创建和销毁线程的步骤,但是如果,我们通过实现Runnable接口这种方式去实现多线程的话,就可以通过线程池中的线程去执行任务,同一个线程可以被重复使用,这样就减少了在线程在创建和销毁上的消耗。

3)Java不支持双继承:一旦继承了Thread类,就无法再去继承其他的类,会降低程序的可扩展性,比如我们要继承一个基类。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章