- 线程和进程的区别
- 并发与并行的区别
- 线程创建方式
- runnable和callable的区别
- run()和start()的区别
- 线程包括哪些状态,状态之间如何变化
- 新建三个线程,如何按顺序执行
- notify()和notifyAll()的区别
- wait和sleep方法的区别
- 如何停止一个正在运行的线程
一、线程和进程的区别
根本区别:进程是操作系统资源分配的基本单位,线程是CPU任务调度和执行的基本单位
对比
- 进程是正在运行程序的实例,一个进程可以包含多个线程,不同线程执行不同任务
- 各个进程拥有独立的内存资源,同一个进程下的所有线程共享当前进程内存资源
- 对比进程,线程没有操作系统为其分配的独立内存空间,而是共享进程的内存空间,更加轻量,上下文切换成本更低。
二、并行和并发的区别
在多核CPU下
并行:同一时间做多件事的能力,4核CPU同时执行4个线程
并发:同一时间只处理一个线程,各线程上下文快速切换
并发是逻辑上的同时发生(切换速度很快,感受不到)
并行是物理上的同时发生
三、线程创建的方式
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- 通过线程池创建
3.1、继承Thread类
- 创建Thread子类
- 子类重写run方法
- 创建子类对象
- 子类对象调用start()开启线程
3.2、实现Runnable接口
- 创建Runnable实现类
- 重写run方法
- 实例化Runnable实现类对象
- 以该对象作为构造器参数构造Thread类
- 调用Thread对象的start()方法开启线程
3.3、实现Callable接口
- 创建Callable实现类
- 重写call方法
- 实例化Callable实现类对象
- 将Callable实现类对象作为参数构建FutureTask对象
- 将FutureTask对象作为构造器参数创建Thread对象
- 调用Thread对象的start()方法开启线程
- 通过FutureTask对象的get()方法获取call方法返回值
3.4、通过线程池创建
四、 runnable和callable的区别
对比一下
1、方法名不同,Runnable为run方法,Callable为call方法
2、返回值不同,Runnable无返回值,Callable返回泛型,可配合FutureTask拿到返回结果
3、异常处理不同,Runnable异常需要内部处理,不能抛出。Callable可以抛出
五、run()和start()的区别
“start()方法会使得该线程开始执行;java虚拟机会去调用该线程的run()方法。”
因此,t.start()会导致run()方法被调用,run()方法中的内容称为线程体,它就是这个线程需要执行的工作。
用start()来启动线程,实现了真正意义上的启动线程,此时会出现异步执行的效果,即在线程的创建和启动中所述的随机性。‘
而如果使用run()来启动线程,只是单纯的执行重写后的run方法,没有开启新线程。
- start():使新线程开始执行,jvm 自动调用该线程run()方法。异步操作
- run():单纯的执行重写后的run方法,没有开启新线程。同步操作
六、线程包括哪些状态,状态之间如何变化
Thread类中的枚举类State里有介绍了线程的六种状态
新建状态、可执行状态(阻塞状态、等待状态、计时等待状态)、死亡状态
NEW ==> RUNNABLE ==> BLOCKED ==> WAITING ==> TIMED_WAITING ==> TERMINATED
简单来讲可以看出三个状态:新建状态、可执行状态、死亡状态
new Thread是新建状态(NEW),调用start()方法后进入可执行状态(RUNNABLE),拿到CUP执行全后进入死亡状态(TERMINATED),如果没有拿到CPU执行权,可能进入如下三种状态
- 当前线程无法拿到锁,进入阻塞状态(BLOCKED),获得锁之后恢复可执行状态
- 当前线程调用了wait()方法,进入等待状态(WAITING),其它线程调用nitify()唤醒后可恢复执行状态
- 当前线程调用了sleep()方法,进入计时等待状态(TIMED_WAITING),到时间后恢复可为执行
七、新建三个线程,如何按顺序执行
使用join方法
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println("t1");
});
Thread t2 = new Thread(() -> {
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2");
});
Thread t3 = new Thread(() -> {
try {
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t3");
});
t2.start();
t3.start();
t1.start();
join方法加了synchronized,保证串行执行。
- 如果参数为负数,则直接报错:"timeout value is negative"
- 如果join方法参数为0,则会调用isAlive()方法,检测线程是否存活,如果存活就调用wait方法,一直等待。
- 如果参数大于0,使用while判断线程是否存活,存活的话就一直判断当前线程执行的时间并且计算还需要等待的时间,如果等待时间小于等于0就跳出循环,否则就继续wait
八、notify()和notifyAll()的区别
锁池:假如线程A拿到了锁,则B进入阻塞状态,进入锁池,等待锁释放
等待池:A拿到锁后执行wait方法,释放锁,进入等待池