多线程学习
什么是进程
当我们开启一个程序的时候就会开启一个进程
Win:可以直接打开任务管理器,查看进程
Linux:PS kill-9
在进程中至少开启一条一个线程,该线程就是主线程
进程
就是所有线程的集合
什么是线程
线程
就是程序执行的路径
在进程中开启一条线程执行我们的代码,程序执行的顺序必须遵循、从上往下的顺序
注意
:如果开启了多线程代码的执行顺序就不是从上往下的顺序
什么是多线程
也就是在同一个进程中,开启了多条不同的执行执行路径,每条执行路径相互不影响,同时执行
多线程的好处
就是提高程序的执行效率 同时,并行
对线程的应用场景
-
异步的发送短信 ,快速的提高响应,提高用户体验
-
异步的实现记录日志
-
对我们后端比较耗时间的代码用异步实现
都是同一个的思想,快速提高http协议的响应,对用户体验比较好
为什么后端开发要使用异步多线程
因为http协议是同步的,如果后端服务器长期没有相应,就会导致客户端一直等待,很影响体验
单线程和多线程执行上有什么区别
单线程
的代码执行顺序就是从上往下执行的,如果中间某个环节一旦出现错误的情况,整个程序直接中断
整个代码的执行效率偏低
多线程
:也就是采用多条不同的代码执行我们的代码程序,每个线程之间互不影响,提高响应速度
如何理解CPU切换线程的概念
对于如果使用单核cpu服务器,开启多线程的情况下,并不是真正意义上的多线程 ,因为单核cpu服务器在同一时刻最多只能运行一个线程,当正在运行的线程切换到另一个线程执行,这个过程叫做cpu切换
线程开的越多越好么?
如果服务器上频繁的开启线程下,对导致cpu不断的切断,降低服务器的性能,如果项目比较小的话,就可以采用多线程,如果比较大的话,建议使用mq实现异步,注意
:如果是高并发的项目,建议使用MQ代替多线程
多线程的创建方式
-
继承
Thread
类重写run方法public class Thread1 extends Thread { /** * 在run方法中实现业务代码 */ @Override public void run(){ System.out.println(Thread.currentThread().getName()+"我是子线程"); } public static void main(String[] args) { System.out.println(Thread.currentThread().getName()+"我是主线程"); //不能直接使用run()方法,这就不属于开启线程,而是调用一个方法 new Thread1().start(); } }
-
实现
Runnable
接口public class Thread2 implements Runnable { /** * 在run方法中实现业务代码 */ @Override public void run() { System.out.println(Thread.currentThread().getName() + "我是子线程"); } public static void main(String[] args) { System.out.println(Thread.currentThread().getName() + "我是主线程"); //这里要通过new Thread()的方式来开启 new Thread(new Thread2()).start(); //简化版 lambdas new Thread(() -> System.out.println(Thread.currentThread().getName() + "我是子线程")).start(); } }
-
可以带返回结果线程接口
Callable
public class Thread3 implements Callable<String> { @Override public String call() throws Exception { try { System.out.println(Thread.currentThread().getName() + "我是子线程"); Thread.sleep(2000); } catch (Exception e) { System.out.println(e.getMessage()); } return "异步调用成功"; } public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> futureTask = new FutureTask<>(new Thread3()); new Thread(futureTask).start(); System.out.println(futureTask.get()); } }
-
线程池
其他扩展方式创建线程
Spring提供异步注解@Asyn
(通过代理模式实现)
用户线程和守护线程的区别
用户线程
当我们主线程停止后,子线程不会停止,用户线程不会随着主线程停止
守护线程
当主线程停止以后,子线程也会停止
守护线程应用场景:GC线程回收垃圾
public class Thread4 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true) {
}
});
//true 守护线程 默认是false 用户线程
//thread.setDaemon(true);
thread.start();
System.out.println(Thread.currentThread().getName() + "线程执行结束");
}
}
线程停止
public class Thread5 extends Thread {
private volatile boolean flag = true;
@Override
public void run() {
while (flag) {
}
}
/**
* 不能直接使用stop方法,不安全
*/
public void stopThread() {
flag = false;
}
public static void main(String[] args) {
Thread5 thread5 = new Thread5();
thread5.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread5.stopThread();
}
}