温习-多线程

2023-10-30 08:59
文章标签 多线程 温习

本文主要是介绍温习-多线程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 多线程的基本概念
      • 什么是cpu
      • 什么是进程
      • 为什么在进程中还需要线程呢?
      • 为什么需要使用到多线程
      • 使用多线程一定提高效率吗?
      • 同步与异步的区别
      • CPU调度时间片
      • CPU调度算法原理
    • 多线程的应用场景
    • 多线程的创建方式
    • 多线程线程安全安全问题
      • 解决线程安全问题

多线程的基本概念

在讲多线程之前, 我们来了解下cpu,大家都知道关于进程和线程的操作都离不开我们的cpu,可以说我们的线程是运行在cpu之上

什么是cpu

CPU的中文名称是中央处理器,是进行逻辑运算用的
主要由运算器、控制器、寄存器三部分组成,
从字面意思看就是运算就是起着运算的作用,
控制器就是负责发出cpu每条指令所需要的信息,
寄存器就是保存运算或者指令的一些临时文件

什么是进程

在这里插入图片描述
进程是资源分配最小单位,线程是程序执行的最小单位。 计算机在执行程序时,会为程序创建相应的进程,进行资源分配时,是以进程为单位进行相应的分配。每个进程都有相应的线程,在执行程序时,实际上是执行相应的一系列线程。
总结:进程是资源分配最小单位,线程是程序执行的最小单位

从我们生活上来说,进程就是我们使用电脑打开一个程序在这过程中cpu会从硬盘中读取一段程序到内存中就是进程,你打开QQ应用那么cpu就会进行调用硬盘中qq.exe然后进行执行,执行的一些临时文件会保存在内存中,
线程是程序执行的最小单位,在一个进程中可以有多个不同的线程

为什么在进程中还需要线程呢?

同一个应用程序中(进程),更好并行处理
在这里插入图片描述

为什么需要使用到多线程

目的就是为了提高程序开发的效率,
比如:现在一个项目只有小王一个程序员,需要开发功能模块会员模块、支付模块、订单模块。需要的开发周期是30天,但是这个项目比较急10天内要搞定,这个时候我们就可以找小郑、小朱来负责其他两个模块的开发这样就可以大大提高了开发的效率,如果小郑在开发中出现了bug也不会影响其他两人的进度了

并行/串行区别
串行也就是单线程执行 代码执行效率非常低,代码从上向下执行;
并行就是多个线程并行一起执行,效率比较高。

使用多线程一定提高效率吗?

多线程 执行 需要同时执行

不一定,需要了解cpu调度的算法
就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务

如果生产环境中开启几百个或者上千个线程,而我们的服务器核数8核、16核、32核,这么多线程都会在我们这些cpu上做上下文切换

同步与异步的区别

同步概念:就是代码从上向下执行。
异步的概念:单独分支执行 相互之间没有任何影响

CPU调度时间片

1.单核的cpu上每次只能够执行一次线程,如果在单核的cpu上开启了多线程,则会发生对每个线程轮流执行 。
2.Cpu每次单个计算的时间成为一个cpu时间片,实际只有几十毫秒人为感觉好像是
在多线程。
3.对于线程来说,存在等待cpu调度的时候 该线程的状态是为就绪状态,如果被cpu调度则该线程的状态为运行状态
4.当cpu转让执行其他的线程时,则该线程有变为就绪状态。

如果在单核的cpu之上开启了多线程,底层执行并不是真正意义上的多线程。
利用多核多线程性能

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 ThreadDemo01  extends Thread{/*** 线程执行的代码在run方法中*/@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"<run>");try{// 当前子线程阻塞3秒时间Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("阻塞完毕");}public static void main(String[] args) { // main 主线程System.out.println("获取当前主线程"+Thread.currentThread().getName());// 启动线程 调用start() 方法不是run()方法new ThreadDemo01().start(); // start 就绪状态 -- 等待cpu调用new ThreadDemo01().start();System.out.println("主线程执行完毕!");}
}

实现Runnable接口创建线程

public class ThreadDemo02 implements Runnable {public void run() {System.out.println(Thread.currentThread().getName() + ",我是子线程");// }public static void main(String[] args) {new Thread(new ThreadDemo02()).start();}
}

使用匿名内部类的形式创建线程

public class ThreadDemo02 {public static void main(String[] args) {// 使用匿名内部类的形式创建线程 java8的新特性new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + ",>我是子线程<");}}).start();}
}

使用lambda表示创建线程

public class ThreadDemo02 {public static void main(String[] args) {// 使用lambda表示创建线程new Thread(()->{System.out.println(Thread.currentThread().getName() + ",>我是子线程<");}).start();}
}

使用Callable和Future创建线程

public class ThreadCallable  implements Callable<Integer> {
/*  从Java 5开始,Java提供了Callable接口,该接口是Runnable接口的增强版,		Callable接口提供了一个call()方法,可以看作是线程的执行体主要 call()方法可以有返回值。call()方法可以声明抛出异常*/@Overridepublic Integer call() throws Exception {// 默认代码执行非常耗时!!System.out.println(Thread.currentThread().getName() + ",执行计算操作");return 1;}public static void main(String[] args) {ThreadCallable threadCallable = new ThreadCallable();FutureTask<Integer> integerFutureTask = new FutureTask<>(threadCallable);new Thread(integerFutureTask).start();// 我们的主线程要等待我们子线程给我的返回结果Integer result = null;try {result = integerFutureTask.get();} catch (InterruptedException e) {throw new RuntimeException(e);} catch (ExecutionException e) {throw new RuntimeException(e);}System.out.println("结果"+result);}}

使用线程池例如用Executors框架

public class ThreadExectors {public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();executorService.execute(new Runnable() {@Overridepublic void run() {System.out.println("我是子线程");}});}
}

spring @Async异步注解

@Async 底层基于aop+自定义注解实现

@Component
@Slf4j
public class OrderManage {@Asyncpublic void asyncLog() {try {Thread.sleep(3000);log.info("<2>");} catch (Exception e) {}}
}
@RequestMapping("/addOrder")
public String addOrder() {log.info("<1>");orderManage.asyncLog();log.info("<3>");return "3";
}

多线程线程安全安全问题

思考下什么情况下会发生线程安全的问题…

当多线程同时对一个全局变量进行写的操作时,可能会受到其他线程的干扰,就会发生线程安全问题

public class ThreadCount implements Runnable {private static Integer count = 100;@Overridepublic void run() {while (count > 1) {cal();}}private  void cal() {try {Thread.sleep(20);} catch (Exception e) {}count--;System.out.println(Thread.currentThread().getName() + "," + count);}public static void main(String[] args) {ThreadCount threadCount = new ThreadCount();Thread thread1 = new Thread(threadCount);Thread thread2 = new Thread(threadCount);thread1.start();thread2.start();}
}

当前代码开启了两个线程,这两个线程都会执行cal()方法,对全局变量count进行操作,因为事同时进行操作的所以随也不知道是thread1 线程和thread2线程哪个先执行,不清楚这个线程什么时候释放完,就出现了线程安全的问题

解决线程安全问题

思考:如何解决线程安全问题

核心思想:上锁,不管是使用synchronized,Lock,分布式锁其实就是把我们当前这个这块区域进行加锁,保证当前的线程不会被其他线程影响,那在思考一下在实际开发中我们那块代码上需要上锁,比如拿上例代码中为例

休息中

这篇关于温习-多线程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/306808

相关文章

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可

多线程解析报表

假如有这样一个需求,当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完成。 Way1 join import java.time.LocalTime;public class Main {public static void main(String[] args) thro

Java 多线程概述

多线程技术概述   1.线程与进程 进程:内存中运行的应用程序,每个进程都拥有一个独立的内存空间。线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换、并发执行,一个进程最少有一个线程,线程实际数是在进程基础之上的进一步划分,一个进程启动之后,进程之中的若干执行路径又可以划分成若干个线程 2.线程的调度 分时调度:所有线程轮流使用CPU的使用权,平均分配时间抢占式调度

Java 多线程的基本方式

Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):

JAVA- 多线程

一,多线程的概念 1.并行与并发 并行:多个任务在同一时刻在cpu 上同时执行并发:多个任务在同一时刻在cpu 上交替执行 2.进程与线程 进程:就是操作系统中正在运行的一个应用程序。所以进程也就是“正在进行的程序”。(Windows系统中,我们可以在任务管理器中看 到进程) 线程:是程序运行的基本执行单元。当操作系统执行一个程序时, 会在系统中建立一个进程,该进程必须至少建立一个线

多线程篇(阻塞队列- LinkedBlockingDeque)(持续更新迭代)

目录 一、LinkedBlockingDeque是什么 二、核心属性详解 三、核心方法详解 addFirst(E e) offerFirst(E e) putFirst(E e) removeFirst() pollFirst() takeFirst() 其他 四、总结 一、LinkedBlockingDeque是什么 首先queue是一种数据结构,一个集合中

多线程篇(阻塞队列- LinkedBlockingQueue)(持续更新迭代)

目录 一、基本概要 1. 构造函数 2. 内部成员 二、非阻塞式添加元素:add、offer方法原理 offer的实现 enqueue入队操作 signalNotEmpty唤醒 删除线程(如消费者线程) 为什么要判断if (c == 0)时才去唤醒消费线程呢? 三、阻塞式添加元素:put 方法原理 图解:put线程的阻塞过程 四、非阻塞式移除:poll方法原理 dequ