线程基础三问——猫眼真题
线程和进程是项目中常遇到的知识点,面试官对此也是对此类知识点经常考察。其中,线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。今天要说的面试三问是关于线程基础
相关的:
- 线程的三种启动方式
- 线程run和start的区别
- 线程的几种状态,相互之间是如何转化的
线程的三种启动方式
1)继承thread类
代码语言:javascript复制 class MyThread :Thread(){
override fun run() {
super.run()
}
}
fun test(){
var t1=MyThread()
t1.start()
}
2)实现runnable接口
代码语言:javascript复制 class MyRunnable : Runnable {
override fun run() {
}
}
fun test() {
var t1 = Thread(MyRunnable(),"test")
t1.start()
}
3)实现 Callable 接口
代码语言:javascript复制 class MyCallThread : Callable<String> {
override fun call(): String {
return "i got it"
}
}
fun test() {
var task = FutureTask(MyCallThread())
var t1 = Thread(task, "test")
t1.start()
try {
//获取结果
var result = task.get()
} catch (e: Exception) {
}
}
也有人表示其实是两个方法,因为第三个方法FutureTask
也是实现了Runnable
的方法,只不过表现方法不一样,然后带返回值。这个大家面试的时候可以都说上,然后说说自己的见解,毕竟要让面试官多多看到你的知识面。
线程run和start的区别
- start方法,用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体中的代码执行完毕而直接继续执行后续的代码。通过调用Thread类的
start()
方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里的run()
方法 称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。 - run方法,run方法只是类的一个普通方法而已,如果直接调用
Run
方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
简单的说就是:调用start
方法方可启动线程,而run
方法只是thread类中的一个普通方法调用,不会启动新线程,还是在主线程里执行。
线程的几种状态,相互之间是如何转化的
1) 初始状态(New)。新创建了一个线程对象就进入了初始状态,也就是通过上述新建线程的几个方法就能进入该状态。
2) 可运行状态,就绪状态(RUNNABLE)。线程对象创建后,其他线程(比如main线程)调用了该对象的start()
方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu
的使用权。以下几种方式会进入可运行状态:
- 调用start方法。
- 拿到对象锁
- 调用yield方法
3)运行状态(RUNNING)。可运行状态(runnable)的线程获得了cpu 时间片
,执行程序代码。线程调度程序从可运行池中选择一个线程作为当前线程,就会进入运行状态。
4)阻塞状态(BLOCKED)。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。wait,sleep,suspend
等方法都可以导致线程阻塞。
5)死亡状态(DEAD)。线程run()、main()
方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。