02.并发编程基础概念

        在正式学习 Java 的并发编程之前,我们需要熟悉和学习几个并发编程的基础概念。

1 进程和线程

1.1 进程

        我们常说的是应用程序,也就是 app,由指令和数据组成。但是当我们不运行一个具体的 app 时,这些应用程序就是放在磁盘(也包括 U 盘、远程网络存储等等)上的一些二进制的代码。一旦我们运行这些应用程序,指令需要运行,数据需要读写,就必须将指令加载至 CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备,从这种角度来说,进程就是用来加载指令、管理内存、管理IO 的。

        当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。

        进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、画图、浏览器等),有的程序只能启动一个实例进程(如有道云笔记、360 安全卫士等)。显然,程序是死的、静态的,进程是活的、动态的。进程可以分为系统进程和用户进程。凡是用于完成操作系统的各种功能的进程就是系统进程,它们就是处于运行状态下的操作系统本身,用户进程就是所有由用户启动的进程。

        站在操作系统的角度,进程是程序运行资源分配(以内存为主)的最小单位。

1.1.1 进程间的通信

        同一台计算机的进程通信称为 IPC(Inter-process communication),不同计算机之间的进程通信被称为R(mote)PC,需要通过网络,并遵守共同的协议,比如 Dubbo 就是一个RPC 框架,而 Http 协议也经常用在 RPC 上,比如 SpringCloud 微服务。

进程间通信有几种方式?

  • 管道:分为匿名管道(pipe)及命名管道(named pipe):匿名管道可用于具有亲缘关系的父子进程间的通信,命名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
  • 信号(signal):信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一致的。
  • 消息队列(message queue):消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息。
  • 共享内存(shared memory):可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。
  • 信号量(semaphore):主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段。
  • 套接字(socket):这是一种更为一般得进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。同一机器中的进程还可以使用 Unix domain socket(比如同一机器中 MySQL 中的控制台mysql shell 和MySQL 服 务程序的连接),这种方式不需要经过网络协议栈,不需要打包拆包、计算校验 和、维护序号和应答等,比纯粹基于网络的进程间通信肯定效率更高。

1.2 线程

        一台电脑通常会运行很多的程序,我们CPU 又是有限的,如何让有限的 CPU 运行这么多程序呢?就需要一种机制在程序之间进行协调,也就所谓 CPU 调度。 线程是 CPU 调度的最小单位。

        线程必须依赖于进程而存在,线程是进程中的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的、能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。一个进程可以拥有多个线程,一个线程必须有一个父进程。

        线程,有时也被称为轻量级进程 (Lightweight Process,LWP),早期 Linux 的线程实现几乎就是复用的进程,后来才独立出自己的API。

1.2.1 Java 中线程无处不在

        在 Java 中不管任何程序都必须启动一个main 函数的主线程;在 Java Web 开发里面的定时任务、定时器、JSP 和 Servlet、异步消息处理机制,远程访问接口 RMI 等, 任何一个监听事件,onclick 的触发事件等都离不开线程和并发的知识。

1.2.2 CPU 核心数和线程数的关系

        前面我们说过,目前主流 CPU 都是多核的,线程是 CPU 调度的最小单位。同一 时刻,一个 CPU 核心只能运行一个线程,也就是 CPU 内核和同时运行的线程数是 1:1 的关系,也就是说 4 核CPU 同时可以执行 4 个线程的代码。但 Intel 引入超线程技术后,产生了逻辑处理器的概念,使核心数与线程数形成1:2 的关系。在我们前面的 Windows 任务管理器贴图就能看出来,内核数是 4 而逻辑处理器数是8。

        在Java 中提供了 Runtime.getRuntime().availableProcessors(),可以让我们获取当前的CPU 核心数,注意这个核心数指的是逻辑处理器数。

public class CPUCores {
    public static void main(String[] args) {
        int cores = Runtime.getRuntime().availableProcessors();
        System.out.println("CPU cores: " + cores);
    }
}

 CPU cores: 8

        获得当前的 CPU 核心数在并发编程中很重要,并发编程下的性能优化往往 和CPU 核心数密切相关。

2 并行和并发

        有了多线程和多核 CPU 之后就有了并发和并行。

        举个例子,如果有条高速公路 A 上面并排有 4 条车道,那么最大的并行车辆就是 4 辆此条高速公路A 同时并排行走的车辆小于等于 4 辆的时候,车辆就可以并行运行。CPU 也是这个原理,一个 CPU 相当于一个高速公路 A,核心数或者线程数就相当于并排可以通行的车道。

        当谈论并发的时候一定要加个单位时间,也就是说单位时间内并发量是多少?离开了单位时间其实是没有意义的。

        并发Concurrent:指应用能够交替执行不同的任务,比如单 CPU 核心下执行多线程并非是同时执行多个任务,而是多个任务交替执行,比如开两个线程执行,CPU 在肉眼不可能察觉到的速度不断去切换这两个任务,以达到"同时执行效果",单核 CPU 的"同时执行效果"是对我们的一种“欺骗”,只是计算机的速度太快,我们无法察觉到而已。

        并行Parallel:指应用能够同时执行不同的任务,比如坐地铁的时候可以看书,这两件事情可以同时执行 。

        两者区别:一个是交替执行,一个是同时执行,如下图所示。

3 上下文切换(Context switch)

        既然操作系统要在多个进程(线程)之间进行调度,而每个线程在使用 CPU 时总是要使用CPU 中的资源,比如 CPU 寄存器和程序计数器。这就意味着,操作系统要保证线程在调度前后的正常执行,所以,操作系统中就有上下文切换的概念,它是指CPU(中央处理单元)从一个进程或线程到另一个进程或线程的切换。

        上下文是 CPU 寄存器和程序计数器在任何时间点的内容。

        寄存器是 CPU 内部的一小部分非常快的内存(相对于CPU 内部的缓存和CPU 外部较慢的RAM 主内存),它通过提供对常用值的快速访问来加快计算机程序的执行。

        程序计数器是一种专门的寄存器,它指示 CPU 在其指令序列中的位置,并保存着正在执行的指令的地址或下一条要执行的指令的地址,这取决于具体的系统。

        上下文切换可以更详细地描述为内核(即操作系统的核心)对 CPU 上的进程 (包括线程)执行以下活动:

  1. 暂停一个进程的处理,并将该进程的 CPU 状态(即上下文)存储在内存中的某个地方。
  2. 从内存中获取下一个进程的上下文,并在 CPU 的寄存器中恢复它。
  3. 返回到程序计数器指示的位置(即返回到进程被中断的代码行)以恢复进程。

        从数据来说,以程序员的角度来看,是方法调用过程中的各种局部的变量与资源;以线程的角度来看,是方法的调用栈中存储的各类信息。

        引发上下文切换的原因一般包括:线程、进程切换、系统调用等等。上下文切换通常是计算密集型的,因为涉及一系列数据在各种寄存器、缓存中的来回拷贝。就CPU 时间而言,一次上下文切换大概需要5000~20000 个时钟周期,相对一个简单指令几个乃至十几个左右的执行时钟周期,可以看出这个成本巨大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/647068.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安装pip install xmind2image失败,4种安装pip install xmind2image在temunx高级终端的失败,却又意外发现

~ $ ~ $ ![在这里插入图片描述](https://img-blog.csdnimg.cn/b59cbb49c3e14a3bbec5675164a14009.png)#!/bin/bash # 创建一个新的空白XMind文件 xmind_dir ( m k t e m p − d ) x m i n d f i l e n a m e ′ t e s t . x m i n d ′ x m i n d p a t h " (mktemp -d…

生命在于学习——Python人工智能原理(1.2)

一、人工智能的基本知识 6、新一代人工智能驱动因素 (1)数据量爆发性增长。 (2)计算能力大幅提升 (3)深度学习等算法发展 (4)移动AI创新应用牵引 7、人工智能关键技术 &#x…

Value-Based Reinforcement Learning(1)

Action-Value Functions Discounted Return(未来的reward,由于未来存在不确定性,所以未来的reward 要乘以进行打折) 这里的依赖actions ,和states 这里 Policy Function : ,表达了action的随机性 S…

压缩能力登顶 小丸工具箱 V1.0 绿色便携版

平常录制视频或下载保存的视频时长往往都很长,很多时候都想要裁剪、 截取出一些“精华片段”保留下来,而不必保存一整个大型视频那么浪费硬盘空间… 但如今手机或电脑上大多数的视频剪辑软件,切割视频一般都要等待很长时间导出或转换&#…

【Text2SQL】Spider 数据集

论文:Spider: A Large-Scale Human-Labeled Dataset for Complex and Cross-Domain Semantic Parsing and Text-to-SQL Task ⭐⭐⭐⭐⭐ EMNLP 2018, arXiv:1809.08887 Dataset: spider GitHub: github.com/taoyds/spider 一、论文速读 本文提出了 Text2SQL 方向的…

Linux更改系统中的root密码

Linux里面的root密码忘记了怎么办? 1 更改系统中的 root 密码 (1)键盘 CtrlAltT 快捷键打开终端。 (2)在终端窗口中输入以下代码: sudo passwd root (3)输入锁屏密码 &#xf…

C#同花顺下单 模拟操作版接口实现

C#同花顺下单 模拟操作版接口的实现 采用C#编程语言实现,对同花顺下单界面自动控制,将实现方法封装为DLL可以任意使用,支持几乎所有券商,不需要更换特定的券商。 比如当下最流行的QMT量化软件,仍然受限于特定的券商&a…

化学中的不确定性。

化学中的不确定性TOC 基于元素分析的无机化学的理论大厦应该说早已落成了,但是却仍然存在着一些列的难解甚至是无解问题,这些大多是在使用理论解释现象时遇到的困难,有些则是在生产实践中生产工艺和生产工序设计和优化中发现的问题。于是&…

MT3040 矩形覆盖

代码&#xff1a; #include <bits/stdc.h> using namespace std; typedef long long ll; const int N 3e5 10; int n, ans, d, w; stack<int> s; // 单调栈 // 如果楼高度类似121&#xff08;凸&#xff0c;两边相等&#xff0c;中间比两边的大&#xff09;&…

一个月速刷leetcodeHOT100 day11 链表完全解析 以及链表5道easy题

链表 表是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点&#xff08;链表中每一个元素称为结点&#xff09;组成&#xff0c;结点可以在运行时动态生成。每个结点包活两个部分&#xff1a;一…

SQL Server2019安装步骤教程(图文)_最新教程

一、下载SQL Server2019 1.到微软官网下载SQL Server Developer版本&#xff0c;官网当前的2019版本下载需要注册账号。 不想注册的朋友&#xff0c;可以选择从网盘下载&#xff1a;点击此处直接下载 2.下载之后先解压&#xff0c;解压后执行exe安装程序。打开之后的界面如下…

元组推导式

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 使用元组推导式可以快速生成一个元组&#xff0c;它的表现形式和列表推导式类似&#xff0c;只是将列表推导式中的“[]”修改为“()”。例如&#xf…

基础6 探索JAVA图形编程桌面:集合组件详解

我们的团队历经了数不胜数的日夜&#xff0c;全力以赴地进行研发与精心调试&#xff0c;最终成功地推出了一款具有革命性意义的“图形化编程桌面”产品。这款产品的诞生&#xff0c;不仅极为彻底地打破了传统代码开发那长久以来的固有模式&#xff0c;更是把焦点聚集于解决长期…

第12章-ADC采集电压和显示 基于STM32的ADC—电压采集(详细讲解+HAL库)

我们的智能小车用到了ADC测量电池电压的功能&#xff0c;这章节我们做一下。 我们的一篇在这里 第一篇 什么是ADC 百度百科介绍&#xff1a; 我们知道万用表 电压表可以测量电池&#xff0c;或者电路电压。那么我们是否可以通过单片机获得电压&#xff0c;方便我 们监控电池状…

Midjourney Describe API 使用文档

Midjourney Describe API 使用文档 Midjourney Describe API 的主要功能是通过上传图片&#xff0c;获取对图片的描述。使用该 API&#xff0c;只需要传递图片文件&#xff0c;API 会返回图片的详细描述。无需繁琐的参数设置&#xff0c;即可获得高质量的图片描述。 支持多种图…

第86天:代码审计-PHP项目TP框架安全写法1day利用0day分析

案例一&#xff1a; 利用框架漏洞-TP3框架-SQL注入&Demo&YxtCMF 首先先查询thinkphp的版本 去寻找版本漏洞: Thinkphp3.2.3及以下版本漏洞整理_thinkphp3.2.3漏洞-CSDN博客 去查这个exp注入 这里的利用条件是必须有find方法&#xff0c;并且where后面的参数是数组 …

网络模型-BFD与网络协议联动

一、BFD:双向转发检测 双向转发检测BFD(Bidirectional Forwarding Detection)是一种全网统一的检测机制&#xff0c;用于快速检测、监控网络中链路或者IP路由的转发连通状况。 1、BFD优点: 对相邻转发引擎之间的通道提供轻负荷、快速故障检测。这些故障包括接口数据链路&#…

【全开源】赛事报名系统源码(Fastadmin+ThinkPHP和Uniapp)

基于FastadminThinkPHP和Uniapp开发的赛事报名系统&#xff0c;包含个人报名和团队报名、成绩查询、成绩证书等。 构建高效便捷的赛事参与平台 一、引言&#xff1a;赛事报名系统的重要性 在举办各类赛事时&#xff0c;一个高效便捷的报名系统对于组织者和参与者来说都至关重…

【数学代码】求两点之间的距离

Hello&#xff01;大家好&#xff0c;今天讲讲求两点之间的距离。 已知点A的坐标为&#xff08;x1,y1&#xff09;,点B的坐标为&#xff08;x2,y2&#xff09;&#xff0c;求两点之间的直线距离。 首先&#xff0c;我先讲明&#xff0c;要解决这个问题&#xff0c;需要用到勾…

八种单例模式

文章目录 1.单例模式基本介绍1.介绍2.单例模式八种方式 2.饿汉式&#xff08;静态常量&#xff0c;推荐&#xff09;1.基本步骤1.构造器私有化&#xff08;防止new&#xff09;2.类的内部创建对象3.向外暴露一个静态的公共方法 2.代码实现3.优缺点分析 3.饿汉式&#xff08;静态…