Runnable接口
我们看Thread类的定义知道,Thread类实现了Runnable接口
Runnable接口的定义如下:
它只有一个抽象方法run。说明需要其实现类重写这个run方法,而run()之间的内容,就是我们期望这个线程该干什么。
同时Runnable接口还被@FunctionalInterface注解标注,说明它是一个函数式接口。这意味着,可以使用Lambda表达式来创建Runnable接口的实例。
线程创建
在Java中,创建一个线程的方式,有且仅有一种方式:
创建一个Thread类实例,并调用它的start方法。
Thread的构造函数
Thread的构造函数有8个,主要就是给四个参数赋不同的值,这四个参数分别是:
① ThreadGroup g (线程组)
② Runnable target(Runnable对象)
③ String name(线程的名字)
④ long stackSize(为线程分配的栈的大小,若为0则表示忽略这个参数)
我们最常用的就是 ②③
对于线程的名字,其默认值为:“Thread- ” +nextThreadNum()。
nextThreadNum():
就是一个简单的递增计数器,如果我们创建线程时没有指定线程名,那线程名就会是:Thread-0,Thread-1,Thread-2....
至此,虽然Thread的构造函数很多,但对我们来说,真正的参数只有一个:
Runnable target(Runnable对象)
前面我们说过Thread类实现了Runnable接口,所以它必定会重写run(),我们来看一下,Thread类中的run():
可以看到,其实在Thread类的run(),还是调用了Runnable的run(),即如果我们在创建线程时,没有传入target,则这个run方法就什么也不会做。
启动线程
在创建完线程后,我们就要启动线程,启动一个线程必须调用线程的start()
start()方法本质调用了start0(),start0()方法是一个本地方法,这个方法使得线程开始执行,并由JVM来执行这个线程的run方法,结果就是有两个线程在并发执行,一个是当前线程,也就是调用了Thread类中的start方法的线程,另一个线程就是当前你Thread对象代表的线程, 它执行了run()。
也就是说,这个Thread类实例代表的线程最终会执行它的run方法。
这个时候就出现了问题:
当我们调用start()后,到最后还是执行了run(),那为什么我们一开始不直接调用Thread类中的run或target对象的run()呢?
这样做是为了使用我们的多线程。Thread类从定义上看就是我们的一个普通的类,是什么东西让一个普通的类变成能创建多线程的类呢?
是native方法!
如果我们直接调用Thread类中的run()或target中的run(),仅仅是一个普通的调用,但是如果我们调用了start(),start方法内部会调用一个本地方法start0(),它将导致一个新的线程被创建出来,而我们的Thread实例,就代表了这个新创建出来的线程,并由这个新创建出来的线程来执行Thread实例的run()。
实战
创建线程的方式一:继承Thread类
① 自定义一个类继承Thread类,并重写run()。
class ThreadHandler extends Thread{

本文详细介绍了Java中创建线程的两种方式:继承Thread类和实现Runnable接口,并分析了start()方法的重要性,强调了直接调用run()与调用start()的区别,最后总结了正确启动线程的方法。
最低0.47元/天 解锁文章
5185

被折叠的 条评论
为什么被折叠?



