文章目录
需要掌握的内容
1.线程的一般创建方法(三种方式),Thread两种创建方式的源码
2.线程的重要api
3.线程的状态
4.线程应用:异步调用,同步等待,并行计算,统筹规划
5.线程的原理:运行流程,重要概念
6.两阶段终止的写法和作用
1. 进程与线程
1.1 进程和线程都是个啥
1.资源分配的角度:进程是系统资源分配的最小单位,而引入线程后线程是是资源调度的最小单位
2.从包含关系角度:进程是线程的容器,一个进程可以分为多个线程
3.从原理角度:进程可以看成外存中程序在内存中的实例,程序被运行,就开启了一个进程,可以加载指令,管理内存和IO。而线程是一个指令流,将一条条指令按照一定顺序交给cpu来执行。
4.二者关系:进程所被分配的资源由它内部的线程共享,进程间通信比较复杂,而线程通信比较简单。上下文切换的开销线程比进程更低。
2.并行与并发
单核CPU将时间分成小片给不同的线程来使用,只是我们看来是同时运行,这种过程称之为为并发Concurrent。
多核CPU,不同的核心可以调度运行线程,那么真正意义上实现了同时运行,称之为并行
3.线程的运行
3.1 线程的创建
3.1.1 直接使用Thread类
// 构造方法的参数是给线程指定名字
Thread t1 = new Thread("t1") {
@Override
// run 方法内实现了要执行的任务
public void run() {
log.debug("hello");
}
};
t1.start();
3.1.2 使用Runnable与Thread
// 创建任务对象
Runnable task2 = new Runnable() {
@Override
public void run() {
log.debug("hello");
}
};
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();
//lambda表达式
// 创建任务对象
Runnable task2 = () -> log.debug("hello");
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();
既然可以直接创建,为什么还要实现Runnable接口?这有什么好处吗?
1、分离了线程代码和任务代码,例如在有多个相同任务的不同线程分享同一个资源的情况下更容易实现,减少重复代码
2、实现了Runnable接口,显然还可以继承别的类,编码更加灵活
3.1.3 使用FutureTask与Thread
FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况
// 创建任务对象
FutureTask<Integer> task3 = new FutureTask<>(() -> {
log.debug(