多线程核心知识之开启线程的多种姿势
说到开启线程的姿势,你的脑海中闪过的是几种方式?是两种?还是三种?还是四种五种六种?我想机智的你肯定第一时间会先去百度看看,毕竟是互联网时代嘛~那我们先一起百度去看看网上大家说的都是几种呢?
我们可以看到百度上大多数人说的都是为三种方式,第一种是继承Thread类,第二种是实现Runnable接口,第三种是实现Callable接口。还有的人说线程池也可以开启线程,我不禁怀疑,到底谁是对的呢。。。
既然大家都是众说纷纭,那我们还是相信官方的说方法,一起去ORCLE官网去看看是怎么说的(ORCLE THREAD OBJECTS),下面我直接选取了官网说两种方式截图贴在了下面,大家一起来看看
仔细一看,竟然是全英文的,内心不禁卧槽了一句,那让我来翻译一下ORCLE主要说的是什么
每一个线程都是Thread实例,并发应用中有两种不同的线程创建策略
1.直接控制线程的创建与管理,每个应用程序需要执行异步任务的时候就为其创建一个线程
2.将线程的管理从应用程序中抽象出来作为执行器,应用程序将任务传递给执行器,由执行器负责执行
这段话简单翻译过来的意思是要么你创建一个线程,要么你创建一个执行器,然后再将任务传递给执行器,显而易见,官网给出的答案就是2种,分别为继承Thread类和实现Runnable接口,那咱们废话不多说,直接开始撸代码。
首先咱们开始演示的为继承Thread类
package com.zhou.threadknowledge;
/**
* FileName: createThreadByExtends
*
* @author mozzie
* @date 2020/4/14 11:50
* description: 重写Thread类中的run方法
*/
public class CreateThreadByExtends extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
public static void main(String[] args) {
CreateThreadByExtends thread = new CreateThreadByExtends();
thread.run();
thread.start();
}
}
接着咱们开始演示实现Runnable接口
package com.zhou.threadknowledge;
/**
* FileName: CreateThreadByImplements
*
* @author zhou
* @date 2020/4/14 11:54
* description: 实现Runnable接口
*/
public class CreateThreadByImplements implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
public static void main(String[] args) {
CreateThreadByImplements runnableThread = new CreateThreadByImplements();
Thread thread = new Thread(runnableThread);
thread.start();
}
}
以上两种就是绝对官方创建线程的方式,可是小伙伴们再仔细看看却也不难发现,说是两种,其实本质上是只有一种方式,为何这么说,我们不妨走进去继续看看源码是怎么写的
/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
我截取了Thread类中的run方法,发现方法一即继承Thread类然后重写run方法,方法二中实现runnable接口并传入Thread类,其实本质并没有任何区别,最终都是调用了Thread类中的start方法,这两个方法的主要区别即是run方法的来源不同而已。
我们再接着去看例如线程池、定时器,也会发现万变不离其宗,无非是上面两种方法的变种而已
由此可知,本质上创建线程只有一种方式,就是新建Thread类,但是类里面的run方法有两种的实现方法,方法一为继承Thread类重写run方法,方法二为实现Runnable接口中的run方法,然后再把该实例传给Thread类,除此之外,线程池,定时器,甚至Lamabda表达式都是通过这两种方式,本质都逃离不了这两个方法。
本问阐释了多线程中如何用正确的姿势去创建多线程,但是创建多线程中继承Thread类与实现Runnable接口我到底又应该选择哪种呢?这两个到底有何区别呢?我既然已经创建了多线程那么又如何去开启多线程呢?我会在后续文章中进行进一步的阐释,请大家持续关注哟~