一.什么是进程
当我们启动一个应用程序,就会开启一个进程。
win:任务管理器
linux:ps kill-9
在进程中至少有一条线程,该线程就是主线程。
进程就是我们所有线程的的集合。
二.什么是线程
线程就是一条程序的执行路径。
在进程中开启一条线程执行我们的程序代码,程序的执行顺序必须遵循从上往下的顺序。
注意:如果是多线程的情况下,代码的执行顺序就是从上往下执行。
三.什么是多线程
也就是再同一个进程中开启了多条不同的执行路径,每条执行路径相互不影响,同时执行。
四.多线程有哪些好处
能够帮助我们实现提高程序的效率,是同时的并行的。
五.多线程哪些应用场景。
1.异步的实现发送短信,快速提高相应,对用户的体验非常好。
2.异步的实现记录日志。
3.支付中异步的回调。
4..对我们后端接口中比较耗时的代码都可以采用异步实现
都是同一个思想:能够快速提高http协议的实现。
http属于同步 (请求request) 响应 Response
六.后端开发为什么需要使用多线程
因为我们http协议默认都是采用同步形式, 整个过程都是基于请求与响应过程,
如果服务器端没有及时的响应客户端的情况下,就会造成浏览器或者客户端一直等待,这样就对用户体验是非常的不友好。
七.单线程和多线程有哪些区别
单线程的代码执行顺序就是从上往下执行,如果中间环节一旦出错,整个程序中断操作。
整个代码的执行顺序偏低。
//单线程 login() { //查询数据库 findDbLogin(userName.pwd); -2s //记录登录日志 login(log); --2s //发送邮件 sendEmail(emali); --2s //发送短信 sendSms(phone) -2s }
总共需要8s完成
多线程:采用多条不同的线程执行程序,每个线程之间互不影响。不同的路径可以提高程序的效率
八.如何理解CPU切换线程的概念
对于如果使用单核CPU服务器,开启多线程的情况下,并不能够真正意义的的多线程, 因为单核CPU服务器在同一时间,最多只能运行一个线程,当正在运行的线程快速切换到另外的一个线程执行,这个过程可以称为CPU切换。
如果是多核处理器,比如i7 8700K处理器 6核12 线程,相当于在于同一时刻可以支持12线程同时访问。如果服务核数越多,对应的线程越多,可以减少cpu切换。
注意:如果我们的在使用单核处理器,并不是真正意义的多线程,底层CPU会不断的切换,切换的过程认为感知好像是多线程。
专门服务器,16核,32线程,32核 64线程
九.并发编程如何优化减少Cpu切换线程。
1.无锁机制。2.优化硬件。3.少用线程。
十.多线程真的是越多越好吗?
如果在服务器上频繁的开启线程的情况下 ,会导致cpu不断的切换, 会影响服务器的性能。
如果项目比较小的情况下, 可以采用多线程实现异步。如果项目比较大的情况建议使用MQ实现异步。
注意:如果高并发的项目建议使用MQ替代多线程。
十一.多线程有哪些创建方式
(1)集成Thead类重写Run方法。
package com.company;
/**
* @Author :guohuan
* @Description:集成Thead类重写Run方法
* @Date :2020/9/14 14:36
*/
public class Thread001 extends java.lang.Thread {
/**
* 在run方法中写线程需要执行的代码
*/
@Override
public void run() {
System.out.println(Thread001.currentThread().getName() + ",我是子线程");
}
public static void main(String[] args) {
System.out.println(Thread001.currentThread().getName() + ",我是主线程");
new Thread001().start();
}
}
(2)实现Runnable接口
package com.company;
/**
* @Author :guohuan
* @Description:实现Runnable接口
* @Date :2020/9/14 14:36
*/
public class Thread002 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ",我是子线程");
}
public static void main(String[] args) {
new Thread(new Thread002()).start();
//写法一
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ",我是子线程");
}
}).start();
//写法二 拉姆达表达式
new Thread(() -> System.out.println(Thread.currentThread().getName() + ",我是主线程")).start();
}
}
(3)实现可以带返回结果线程 Callable
采用异步的去执行线程,但是如果需要获取到该线程执行的结果的情况下,整个过程就变成了一个线程。
package com.company;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @Author :guohuan
* @Description:实现可以带返回结果线程 Callable
* @Date :2020/9/14 14:56
*/
public class MyCallback implements Callable<String> {
@Override
public String call() throws Exception {
try {
System.out.println(Thread.currentThread().getName() + ",正在开始异步发送短信");
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
return "异步执行发送短信";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//可以获取当前线程返回的结果
FutureTask<String> futureTask = new FutureTask<>(new MyCallback());
new Thread(futureTask).start();
//等待线程执行完毕获取结果
System.out.println("result:" + futureTask.get());
}
}
(4) 线程池核心思想 复用线程、管理线程、统一创建和销毁四种实现。
可缓存、可定长度、可定时、单例
package com.company;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @Author :guohuan
* @Description:线程池
* @Date :2020/9/14 15:28
*/
public class Thread003 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> System.out.println(Thread.currentThread().getName() + ",我是线程池"));
}
}
(5)Spring 提供的异步注解@Async Spring异步问题,代理模式实现。