多线程的基本概念
什么是cpu
CPU的中文名称是中央处理器,是进行逻辑运算用的,主要由运算器、控制器、寄存器三部分组成,从字面意思看就是运算就是起着运算的作用,控制器就是负责发出cpu每条指令所需要的信息,寄存器就是保存运算或者指令的一些临时文件,这样可以保证更高的速度。
也就是我们的线程运行在cpu之上。
CPU
什么是线程/进程
进程是资源分配最小单位,线程是程序执行的最小单位。 计算机在执行程序时,会为程序创建相应的进程,进行资源分配时,是以进程为单位进行相应的分配。每个进程都有相应的线程,在执行程序时,实际上是执行相应的一系列线程。
总结:进程是资源分配最小单位,线程是程序执行的最小单位
什么是进程:
1.cpu从硬盘中读取一段程序到内存中,该执行程序的实例就叫做进程
2.一个程序如果被cpu多次被读取到内存中,则变成多个独立的进程
什么是线程:
线程是程序执行的最小单位,在一个进程中可以有多个不同的线程
同时执行。
为什么在进程中还需要线程呢?
同一个应用程序中(进程),更好并行处理。
为什么需要使用到多线程
采用多线程的形式执行代码,目的就是为了提高程序的效率。
目的就是为了提高程序开发的效率
比如:现在一个项目只有一个程序员开发,需要开发功能模块会员模块、支付模块、订单模块。
并行/串行区别
串行也就是单线程执行 代码执行效率非常低,代码从上向下执行;
并行就是多个线程并行一起执行,效率比较高。
使用多线程一定提高效率吗?
多线程 执行 需要同时执行
不一定,需要了解cpu调度的算法
就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务
如果生产环境中开启几百个或者上千个线程,而我们的服务器核数8核
16核 32核,这么多线程都会在我们这些cpu上做上下文切换
上下文切换:
从该线程执行切换到另外的线程 该线程—运行切换为就绪状态。
线程池:和服务器cpu核数 8核 16核
同步与异步的区别
同步概念:就是代码从上向下执行。
异步的概念:单独分支执行 相互之间没有任何影响。
CPU调度时间片
1.单核的cpu上每次只能够执行一次线程,如果在单核的cpu上开启了多线程,则会发生对每个线程轮流执行 。
2.Cpu每次单个计算的时间成为一个cpu时间片,实际只有几十毫秒人为感觉好像是
在多线程。
3.对于线程来说,存在等待cpu调度的时候 该线程的状态是为就绪状态,如果被cpu调度则该线程的状态为运行状态
4.当cpu转让执行其他的线程时,则该线程有变为就绪状态。
如果在单核的cpu之上开启了多线程,底层执行并不是真正意义上的多线程。
利用多核多线程性能。
Cpu密集型/IO密集型
Cpu密集型:长时间占用cpu;例如: 视频剪辑
IO密集型 :cpu计算时间短 访问外接设备时间长
Input/output
CPU调度算法原理
1.先来先服务 缺点如果最先来执行的线程 是CPU密集型 这样话可能会一直
无法继续执行其他的线程。
2.最短作业法 谁的计算时间短,谁先来执行。
3.优先级调度算法 根据重要性将进程分成4个优先级
优先级4 进程D负责画面----
优先级3 进程B和进程C接受用户的指令 重要
优先级2 后台处理器 次要
优先级1
程序计数器
程序计数器是用于存放下一条指令所在单元的地址的地方
多线程的应用场景
多线程的快速入门
1.客户端(移动App端/)开发;
2.异步发送短信/发送邮件
3.将执行比较耗时的代码改用多线程异步执行; 可以提高接口的响应速度
4.异步写入日志 日志框架底层
5.多线程下载
多线程的创建方式
1)继承Thread类创建线程
2)实现Runnable接口创建线程
3)使用匿名内部类的形式创建线程
4)使用lambda表达式创建线程
5)使用Callable和Future创建线程
6)使用线程池例如用Executor框架
7)spring @Async异步注解 结合线程池
继承Thread类创建线程
public class Thread01 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread01: " + i);
}
}
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
Thread01 t1 = new Thread01();
t1.start();
}
}
实现Runnable接口创建线程
public class Runnable implements java.lang.Runnable {
@Override
public void run() {
System.out.println(Thread01.currentThread().getName());
}
public static void main(String[] args) {
Runnable r = new Runnable();
System.out.println(Thread01.currentThread().getName());
Thread t = new Thread(r);
t.start();
new Thread(new Runnable()).start();
}
}
使用Callable和Future创建线程
Callable和Future 线程可以获取到返回结果 底层基于LockSupport
线程 异步执行 比较耗时间-
从Java 5开始,Java提供了Callable接口,该接口是Runnable接口的增强版,Callable接口提供了一个call()方法,可以看作是线程的执行体,但call()方法比run()方法更强大。
call()方法可以有返回值。
call()方法可以声明抛出异常。
callable
public class Callable01 implements java.util.concurrent.Callable<Integer> {
@Override
public Integer call() throws Exception {
try {
Thread.sleep(1000);
}catch (java.lang.Exception e) {
e.printStackTrace();
}
return 1;
}
public static void main(String[] args) throws Exception {
Callable01 callable01 = new Callable01();
System.out.println(Thread.currentThread().getName() + ": Callable01.main()");
FutureTask<Integer> futureTask = new FutureTask<>(callable01);
new Thread(futureTask).start();
futureTask.get();
System.out.println("futureTask.get() = " + futureTask.get());
}
}
使用线程池例如用Executors框架
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1");
}
});
}
spring @Async异步注解
@Async 底层基于aop+自定义注解实现
@Component
@Slf4j
public class OrderManage {
@Async
public void asyncLog() {
try {
Thread.sleep(3000);
log.info("<2>");
} catch (Exception e) {
}
}
}
/**
* http://127.0.0.1:8080/addOrder
*
* @return
*/
@RequestMapping("/addOrder")
public String addOrder() {
log.info("<1>");
orderManage.asyncLog();
log.info("<3>");
return "3";
}
手写 @Async异步注解
package com.gtf.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ThreadAOP {
@Around(value = "@annotation(com.gtf.zj.AsyncZJ)")
public void around(ProceedingJoinPoint joinPoint) {
try {
// 正常需要结合到线程池
new Thread(() -> {
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}, "cs").start();
} catch (Throwable throwable) {
}
}
}
@AsyncZJ
public void add() {
System.out.println("JdkInterfaceImpl.add");
}