1、创建线程有几种方式
我知道的创建线程的方式大体上可以分为四种:
1)继承Thread类并重写run方法创建线程
2)实现Runnable接口并重写run方法
3)实现Callable 接口并重写call方法
4)使用线程池创建
2、runnable和callable的区别
Runnable接口run方法无返回值;Callable接口call方法有返回值
3、start和run的区别
run(): 封装了要被线程执行的代码,本质上就是一个普通方法,可以被调用多次
start(): 用来启动线程,底层会自动去执行run方法中的代码,start方法只能被调用一次
也就是启动线程的时候,只能调用start方法,如果调用的run方法,不会启动新线程,而是当普通方法调用执行
4、notify和 notifyAll的区别
这两个方法都是用户唤醒被wait方法休眠的线程的,区别点在于:
notifyAll:唤醒所有wait的线程
notify:随机唤醒一个 wait 线程
5、sleep 和 wait 的区别
(方法归属不同):sleep是Thread 的静态方法,而wait是Object的成员方法
(醒来时机不同): sleep会在指定的时间后自动苏醒,而wait需要其他线程的唤醒
(锁特性不同):sleep不会释放锁,而wait会释放锁
(使用限制不同):wait必须用在synchronized代码块中,而sleep无此限制
6、说一下线程的状态及转换
在我的理解中,线程共分为7种状态,分别是:新建、就绪、运行以及阻塞、等待、死亡
它们之间的转换关系是这样的:
当线程new出来之后,没有start之前就会处于新建状态
当线程执行start方法之后,就进入就绪状态
当就绪的线程一旦获取到了cpu的执行权,就可以进入运行状态
当线程执行完了run方法之后,就进入了死亡状态
这是一条正常的流程,但是代码在运行状态下可以因为一些原因进入到其它状态,比如说:当进行抢锁操作时,抢锁失败就会进入到阻塞状态
当代码调用了wait或者sleep方法时,就会进入等待状态
这是我对线程状态及其转换的理解
7、现在有T1,T2,T3三个线程,如何保证它们按顺序执行?
用join()方法实现
具体来说就是:可以在t2之前调用t1.join(),在t3之前调用t2.join()
8、synchronized的实现原理是怎样的
在Java中,每个对象都隐式包含一个 monitor(监视器)对象,加锁的过程其实就是竞争 monitor 的过程,
当线程进入字节码monitorEnter指令之后,线程将持有monitor对象,执行monitorExit时释放 monitor 对象
如果在这个过程中,其它线程就会阻塞等待获取该monitor对象
原文链接:https://blog.youkuaiyun.com/qq_17462303/article/details/134470136