C++Prime Plus(1)

article/2025/9/14 6:46:59

目录

  • 1.C++简介
  • 2.程序生成(创建源码,编译和链接)
  • 3.进入C++
  • 4.C++语句
  • 5.函数入门
  • 6.整型
  • 7.char,bool(小整数)
  • 8.const与符号常量
  • 9.浮点数
  • 10.算术表达式
  • 11.数组
  • 12.C风格字符串
  • 13.C++风格字符串
  • 14.结构
  • 15.指针
  • 16.动态内存分配
  • 17.指针运算
  • 18.指针与字符串
  • 19.动态结构
  • 20.数组的替代品

1.C++简介

C++起源:带类的C语言,C++支持3种程序设计方式:过程化程序设计(比如C),面向对象程序设计,泛型程序设计(对变量的数据类型模糊化);

过程化程序设计,类似数学,即算法+数据,用程序语言描述处理数据的过程,为了优化程序的结构,出现了结构化程序设计(自顶向下的设计,程序结构划分为3种:顺序,分支,循环);C语言支持结构化程序设计,C语言可以操作到位,更接近硬件,过去的高级语言通常只能操作到某个变量(在内存中操作)。

面向对象:允许我们设计与问题对应的类。并且提高代码复用性。

泛型程序设计:对于C语言,我们必须规定每个数据的类型,C++可以对数据类型模糊化,统一为T类型。

2.程序生成(创建源码,编译和链接)

源码是程序员写好的程序,用后缀名区分源文件,cpp后缀表示C++源文件,c后缀表示C的源文件。创建源码的方式:在编辑器编辑源文件。现在大家都使用IDE开发,将编辑,编译,链接过程集成到一个软件中。
在VS中,一个软件被称为一个解决方案,解决方案可以包含多个项目(解决方案是项目的容器),每个源文件都是项目的组成部分。
编译:将源文件翻译成机器语言,称为目标文件,目标文件不是可运行的文件;
链接:将目标文件与库的目标文件捆绑,形成可执行文件。
编译链接的方式取决于操作系统和编译器。比如windows+gcc,在命令行输入gcc prog.cpp就能实现编译和链接。在VS中,可以直接”生成解决方案”。

3.进入C++

首先看一个C++的程序示例:
fig1

两种注释: ///*……*/

预处理指令用#开头,编译时先处理预处理指令,再执行编译,比如:#include <iostream>相当于在此处插入iostream的内容,iostream被称为头文件。通常,每个头文件支持一组工具(头文件是库的接口),iostream提供输入输出工具,比如cout输出,传统C++和C风格的头文件后缀为h(stdio.h),新C++风格的头文件不需要后缀。

命名空间:编写大型程序或将多个厂商的代码整合到一起需要的工具,不同厂商的代码中可能有同名的变量和函数,每个厂商的产品封装在自己的命名空间下(ns1::xns2::x)。新C++的标准组件都在命名空间std下(std::cout)。

using编译指令:通知编译器,程序中的标准组件都是某一个命名空间中,不在需要用”命名空间::组件名”的方式,可以直接用”组件名”调用组件。

main函数:C++程序有很多函数组成,但main函数才是执行入口。
函数头:函数的接口,main函数是程序与操作系统之间的接口,函数头由”函数名,返回值,参数”组成,比如int main()
花括号内的是函数体,由一组语句组成,表示函数应该执行哪些计算机指令。
对于cout<<”hello”<<endl<<表示信息流向,hello流向cout,endl流向hello,endl代表重启一行(光标移动到下一行的第一列,也可以用字符’\n’表示)。

4.C++语句

同样看下面示例:
fig2
多了一个变量:程序运行中可以变化的值,变量必须占有存储空间。
变量定义:为变量准备存储空间,为编译器检查变量使用是否正确提供依据。定义格式:”类型 变量列表”,比如int carrots。变量必须先定义再使用。

赋值语句将某个值存放到内存单元,carrots=25,将25存放到carrots对应的内存单元,carrots=carrots-1将carrots对应的内存单元内容减1,再存放到carrots的内存单元。
赋值运算符=:二元运算符(两个运算对象,左右各一个,计算右边表达式的值,存放到左边),右结合的(先执行z=0,再执行y=z,再执行x=y;先执行carrots-1,再执行carrots= carrots-1),比如:

int x, y, x;
x=y=z=0;

cout可以输出变量值:cout<<carrots,其实cout很复杂,它可以取出carrots的内容取出,整数25再转换成字符串”25”输出到显示器。cout可以拼接输出流:cout<<”carrots:”<<carrots<<”end”<<endl

我们可以在运行中用键盘赋值变量,使用cin:

cin>>变量; 或者:
cin>>变量1>>变量2; 

键盘输入变量1的值,回车,再输入变量2的值,再回车,执行后面语句。cin示例如下:
fig3

5.函数入门

函数是程序中的一个零件,可以完成一个功能。

返回值类型 函数名(参数列表)
{语句组合
}

函数可以没有参数,括号内为空或void,函数可以没有返回值,返回值类型用void表示。

函数原型声明:告诉C++编译器,函数的参数和返回值,使编译器可以检查程序对函数的用法是否正确,比如:double sqrt(double); ,函数原型声明出现在每个源文件的开头。

我们可以从库(我们需要include头文件)中调用函数,头文件中的内容是该库中所有函数的原型声明;因此include就是把原型声明插入源文件中。
fig4
函数定义
设计函数头:根据函数的输入输出设计参数和返回值,并给函数命名;
设计函数体:从参数到返回值的计算过程,使用return返回值并退出函数;

无返回值函数实例:
fig5
有返回值的函数示例:
fig6

6.整型

整型是高级语言处理整数的工具(子集)。
fig7
比如unsigned short,也至少占16位,但是由于视为无符号数,则数值的最大值变得更大了,因为最小值变成了0,同样的占位空间获得了更大的数值范围。
整型变量声音如:short score 或 short int score;int number1, number2;

查看整型占有空间的大小:
方法一是sizeof(一元运算符)输出字节占用数:sizeof(类型名或表达式),即sizeof(int), sizeof(score)
方法二是查看头文件climits,该头文件中定义了各种类型长度的符号常量:
fig8
变量在定义时,初始值是随机的(值是创建变量前,该内存块原有的值)。所以为了避免出错,我们最好在变量定义时赋值:
int score=90
初值可以是常量或一个已经定义的变量:
int scoreAvg=80;
int score=scoreAvg;

整型的字面量通常为:十进制,八进制(以0开头,比如0127),十六进制(以0x开头,比如0x18FD)
fig9
C++在处理数值时,统一转换为二进制处理,输出时统一转换为十进制。

对于整型常量,默认为int,超出范围则视为long,超出long则视为long long。我们也可以用后缀明确指出常量类型,比如100L(长整型);其实,对于int scoreAvg=80; 80就是一个整型常量。

7.char,bool(小整数)

char是用于处理字符的类型:字符在机器内用8位整数编码(编码规则:ASCII,ASCII编码的特点是大写字母编码连续,小写字母编码连续,数字字符编码连续)
编程时,不需要关心字符的编码:字符输入(cin>>字符型变量),字符输出(cout<<字符类型变量或字符常量)

字符类型(char类型)的运算:在早期内存昂贵时候,由于char只占一个字节,程序员常将char作为比short小的整型使用,char也可以执行加减和比较运算,参加运算的是内码值。
fig10
char类型常量:
常规字符:用单引号’A’, ‘s’
转义字符:’\n’换行,’\t’水平制表符

char类型示例:
fig11
bool类型:表示逻辑”真”和”假”,bool类型的值(true和false)
bool类型的机器内表示为一个字节,true是1,false是0,bool可以作为算术运算的运算数。
bool不能直接输入输出,直接输出bool类型的值得到的不是true或flase,而是1或0。

8.const与符号常量

符号常量:为程序中的常量取一个名字,称为符号常量;使用符号常量提高了程序的可读性,并且便于管理常量值。

符号常量的定义
用#define定义:#define 符号常量名 字符串(不建议使用这种C的定义方式);
const限定符:限定一个变量是只读的,(const 类型名 符号常量名 = 初值; ),必须有初值,比如:
const double PI=3.14;
符号常量的命名与变量命名相同,为方便区分,符号常量名采用大写。

9.浮点数

浮点数即实数R,浮点数名称的来源:小数点可以移动,比如3.14可表示为 314.0 ∗ 1 0 − 2 314.0*10^{-2} 314.0102或者 0.314 ∗ 10 0.314*10 0.31410

浮点数的表示,浮点数在机器内用二进制表示,我们需要存储两部分,比如 10100 ∗ 2 1101 10100*2^{1101} 1010021101,我们分别保存10100和1101,即尾数和指数;
fig12
浮点常量的表示
十进制与日常表示相同,比如127.7。
科学计数法,尾数E指数 或者 尾数e指数,比如34E-8,-1.5e10,科学计数法用于表示很大或很小的实数。

浮点常量默认是double,我们也可以明确指定浮点常量的类型,比如1.5F(float)与 2.3E10L(long double)

浮点类型的精度示例:
fig13
可以看出float确保7位精度,double则确保15位精度。

10.算术表达式

算术运算符:
fig14
优先级
高:乘,除,取模
低:加,减
我们可以用括号自己选择优先级

同一优先级,算术表达式满足左结合性,先计算左边的运算,再计算右边。

除法的结果取决于运算数:两个整数相除结果为整数,只要有一个运算数是浮点数,则会保留小数部分。
fig15
C++在实际执行时,并不能操作不同类型的数据,前面提到的除法只是被做了类型转换才得以实现。C++本身只能操作int和int,double和double,float和float等等。

自动类型转换出现的场合
1.赋值或初始化时,如果右边的表达式计算结果类型与左边的变量类型不同:右边值被转换成左边变量类型;
2.函数参数传递时,实际参数被转换成形式参数的类型;
3.表达式中的运算数类型不一致,需要遵循转换规则:把精度小的运算数向精度大的运算数转换;

自动类型转换的示例:
fig16
我们也可以进行强制类型转换:
C++的风格为:类型 (表达式)
C的风格为:(类型) 表达式
fig17

11.数组

数组用于存储多个同类型的值;
定义格式为:类型 数组名[元素个数] 或者 类型 数组名[元素个数]={初始值表}
比如:
int array[10]; 数组的元素初值为随机值
double darray[3]={1.1,2.1,3.4}
int iarray[]={1,2,3}; []为不指出元素个数情况,该数组有三个元素
short sarray[10]={0,1,1}; 三个初值给了数组的前三个元素,后面的元素初值统一为0

数组元素的索引:数组名[下标],比如array[5]可以访问第6个元素
fig18
编译器不检查下标的合法性,所以要注意数组的范围,不然会无意修改了内存其他区域的值。

数组示例:
fig19

12.C风格字符串

“programming”就是一个字符串常量,看起来是11个字符,但其实是12个字符,因为C语言中规定字符串以’\0’(空字符)结束。
C用char型数组保存字符串,“programming”由12个元素的数组存储。
如:
char str[]={‘s’, ‘t’, ’r’, ‘i’, ‘n’, ‘g’, ‘\0’}
为了使用简单,C也支持char型数组的简便形式赋值:
char str[]=”string” 或 char str[10]=”string”(剩余元素值为0,即在char型下是空字符’\0’)
fig20
注意,字符串是一个字符数组(char型数组),但字符数组不一定是字符串,字符串必须以’\0’结束。
char cArray[]={‘s’, ‘t’, ’r’, ‘i’, ‘n’, ‘g’} 只是一个字符数组,但不是字符串,空字符串“”虽然没有内容,但是也占用一个字节,存放空字符’\0’。
字符串的输出可以使用cout,cout逐个输出字符串中的字符,直到遇到’\0’:
cout<<字符串常量
cout<<字符串变量(字符型数组,并且以’\0’结束)

字符串的cin输入

对于输入一个单词:
cin>>字符数组名,比如cin>>str,cin以回车字符或者空格字符作为输入结束的标记

对于输入一行:
cin.getline(字符数组名,数组规模)
cin.get(字符数组名,数组规模)
以回车字符或达到数组规模结束输入,区别:getline将回车的换行符丢弃,get会将换行符留在缓冲区放在下一次输入的最开始位置。

在早期C语言没有getline时候,只能使用get,但是get对于读入回车的处理会让人们对字符文本的逻辑容易出错,为了让get每次都只输入一行,并让回车不放在下一次输入的行中,我们使用无参数的cin.get(),cin.get()读入任意一个字符,包含回车。于是常见的输入格式为:
cin.get(str1,80);
cin.get(); //读入cin.get(str1,80);中的回车换行符
cin.get(str2,80); //此次输入的最开始就不再有换行符存在

字符串示例:
fig21
如果把cin.get()注释了:
fig22
我们发现不能输入address,这是因为,当我们输入year后,还有一个回车,这个回车被保留在输入队列,cin.getline(address,80)首先读入回车,误认为已经结束输入。


关于cin>>变量1>>变量2; 键盘输入变量1的值,回车(或者空格),再输入变量2的值,再回车(或者空格),才能执行后面语句;对于cin>>的方式,每一次执行>>前,都是变量值与空格放入缓冲区,变量值被赋值给变量,空格在输入队列中,下一次执行>>时,空格从队列中移除,队列中又是新的变量值+空格,然后变量值被赋值到下一个变量。
fig23
比如我们cin>>year; 我们输入1990,然后回车,1990与回车就被放到输入缓冲区中(队列),我们必须回车了机器才能将1990赋值给year,队列中剩下空格字符;

cin.get和cin.getline都是从缓冲区(输入队列)中读入,键盘的输入也是先进入队列,才被get和getline读到。


13.C++风格字符串

C语言没有字符串类型,所以操作起来是不方便的,因此C++出现了string类型;
string类型:专门处理字符串的类型,在头文件string中,在命名空间std下
fig24
为了输入带空格的字符串,应该使用std::getline(cin, str),注意不是cin.getline

字符串示例:
fig25
可以看到,std::getline(cin, str)也是从缓冲区读,也是先读入了cin>>处引入的空格字符,如果我们在cin>>s1时,最后采用换行,那么getline将读到换行,误认为结束。

14.结构

结构类型:将描述一个复杂对象的多个部分组成一个整体

建立结构声明:描述结构的组成

struct book{char title[MAXTITL];char author[MAXAUTL];float value;
}

我们可以定义结构变量,也可以定义结构数组:book book1; book bookarray[10];
fig26
结构示例:
fig27
结构的成员可以只占若干位,也被称为结构的位字段,位字段的定义为:
类型 变量 : 位数(即bit)
fig28
z指定的位数决定了结构体变量d的大小,当z:29时,占用4个字节,共32位;此时,x,y,z相当于共用一个int变量(1个int刚好32位);
当z:32时,需要使用8个字节,因为结构此时占用35位,需要根据成员类型自动补齐,35位超出1个int的空间,所以要两个int,一个用于存储z,另一个用于x,y的共享;
从int的视角看,成员存在共享,但从bit角度看,每个成员占用的位是不同的。

15.指针

指针:值为内存地址的变量,指针提供了间接访问的方式;

定义指针变量:类型名 *指针变量名,比如int *p;

运算符&:一元运算符,运算对象是变量,运算结果是变量的地址。

int *p, a;
p=&a; //将a的地址赋值给指针变量p

间接访问运算符*:一元运算符,运算对象是指针,运算结果是指针指向的变量,*p=*p * 2;

指针示例:
fig29
指针的注意事项:
fig30

16.动态内存分配

程序通过声明变量通知计算机为它准备好内存空间,这些信息是编译时就能确定的。每个变量对应一块内存空间。变量名是这块空间的名字,程序通过变量名访问对应的空间。

有时候编程时,我们不必为所有变量进行声明。我们可以采用动态内存分配节约空间。
动态内存分配:在程序运行时申请内存和释放内存的功能。

动态内存申请:在内存寻找一块大小合适的空间,返回起始地址。注意,动态分配的内存没有名字,只有地址,只能间接访问。(这也是C++需要指针的一个原因)

动态内存的申请方法:

类型 指针=new 类型 //申请一块保存某种类型数据的内存空间,返回申请到的内存地址
类型 指针=new 类型 [结果值为整数的表达式] //申请一块保存某种类型数组的内存空间,返回申请到的内存地址

fig31
对于int *array = new int [n],实现了动态数组。

内存释放:通过变量声明获得的内存会在存储期结束时回收。但通过动态申请的空间不会被系统自动回收。
释放空间的运算:

delete 指针 //释放动态变量
delete [] 指针 //释放动态数组

delete的重要性:没有delete的动态内存一直被程序占用,特别是,当程序执行结束,这块空间依然被标识为被使用,这被称为内存泄漏。

动态内存示例1,可以看出,指针只是一个用于保存地址的变量,不管指向什么类型的变量,该指针都占用8字节(与操作系统64位有关),由于指针是变量,我们也能够对指针变量取其地址:
fig32
动态内存示例2:
fig33

17.指针运算

指针变量保存的是整数(所指变量的地址),我们可以对指针执行加减运算:
指针加1是加上一个基类型的长度;
指针减1是减去一个基类型的长度;
也就是说,具体是加减多少取决于基类的类型:
fig34
同理,我们写pi=pi+1也是一样的,pi的值增加4;


对于++a和a++:两个表达式的副效应都是令 a 增加 1 。区别在于表达式 a++ 的值是 a 自增前的值, ++a 的值是 a 自增后的值。(所以最好用++a形式)
fig35


指针与数组:数组名就是指针,因此指针运算应该与数组关联才有意义,因为我们可以利用数组名去访问内存;
fig36
但是数组名与指针变量的区别在于,数组名是指针常量,也就是说数组名(指针常量)的地址是不能修改的。

但我们可以将数组名赋给同类型的指针变量:int *ap=a,从而我们将指针变量指向了数组的第一个变量。
fig37
通过指针访问数组的示例:
fig38
sizeof不同的意义在于:注意明确数组和指针的区别,数组名虽然保存了数组首元素的地址,但数组本身是一个连续的变量组合,指针只是存放地址的变量。

18.指针与字符串

C风格的字符串使用一个char型数组存储,并以’\0’作为结束符;

由于数组名是一个指针,所以C风格的字符串可以用一个指向字符的指针表示。通常我们定义指针指向字符串(这个char型数组),并用const限定该指针变量指向的字符串只读(限制我们不能通过指针修改该字符串中的字符);


const 与指针,分为三类:pointer to const,const pointer与const pointer to const
fig39
fig40
fig41


cstring库中的函数以及用cout输出时,都是从数组名对应的地址或从指针指向的地址开始处理到’\0’结束。

字符串示例如下,注意当指针指向char时,与指向其他类型不同,所以我们需要额外留意指针与字符串的读写问题:
fig42
fig43

19.动态结构

运行时通过new申请一个动态的结构变量
fig44
注意在访问动态成员时,(*指针).成员,由于成员运算符优先级高于*运算符,所以要加括号。为了避免疏忽括号的情况,我们可以使用指针运算符->来访问。

动态结构示例:
fig45

20.数组的替代品

C++中有两种数组的替代:vector和array

vector是一种动态数组,可以自动调整长度。
用法:包含头文件vector,定义时,需要指出数据类型和规模,规模可以是变量,不指出规模则规模为0;
fig46
array是效率高于vector的数组,但规模固定,array是C++11新增的类型。
用法:包含头文件array,定义时需要指出类型和规模,规模是常量。
fig47
array和vector相比普通数组的区别在于:array,vector支持整个对象的整体赋值,使用示例如下:
fig48


http://chatgpt.dhexx.cn/article/9vPFoniP.shtml

相关文章

C++Prime Plus(7)

目录 96.输入输出概述97.使用cout输出(1)ostream基本功能98.使用cout输出(2)格式化输出99.使用cin输入100.文件(1)简单的文件IO101.文件打开的进一步讨论102.二进制文件访问103.随机读写 96.输入输出概述 C的输入输出是由库iostream中提供的一组类实现的&#xff1b; 流 C把输…

E-Prime软件包及安装

E-Prime软件包及安装 1 版本问题2 安装过程3 注意事项4 唠唠叨叨 Hello&#xff0c; 这里是行上行下&#xff0c;我是喵君姐姐~ 众所周知&#xff0c;E-Prime是实验设计的执行者。 当我们提出一个想法&#xff0c;则需要一个具体的软件来实现它。 而E-Prime相对于Matlab和Py…

Prime Sample

又发现了个框架 但没有代码啊~~ 还是搬来了&#xff0c;重要样本关注机制&#xff0c;一种新颖的目标检测框架 上论文 论文地址&#xff1a; https://arxiv.org/pdf/1904.04821.pdf 在目标检测框架中&#xff0c;平等对待所有样本并以平均性能最大化目标是一种常见的范例。在…

Prime Factors

此题需要使用到质因子分解的算法&#xff0c;可以参考以下链接&#xff1a; https://blog.csdn.net/qq_42410605/article/details/100150140 题目描述&#xff1a; Given any positive integer N,you are supposed to find all of prime factors,and write them in the form…

SpringBoot实现分布式锁

SpringBoot实现分布式锁 先了解一下线程数&#xff1a; 线程锁 线程锁&#xff1a;主要用来给类&#xff0c;方法&#xff0c;代码加锁&#xff0c;当某个方法或者某块代码使用synchronize关键字来修饰&#xff0c;那么在同一时刻最多只能有一个线程执行该代码&#xff0c;如…

深入理解ConcurrentHashMap原理分析以及线程安全性问题

在之前的文章提到ConcurrentHashMap是一个线程安全的&#xff0c;那么我么看一下ConcurrentHashMap如何进行操作的。 ConcurrentHashMap与HashTable区别&#xff1f; HashTable put()源代码 我们来看一下put 操作&#xff1a; 方法体 被 同步锁标记&#xff0c;由于同步锁的…

Redis分布式锁到底安全吗?

若有收获,请记得分享和转发哦 这篇文章我想和你聊一聊&#xff0c;关于 Redis 分布式锁的「安全性」问题。 Redis 分布式锁的话题&#xff0c;很多文章已经写烂了&#xff0c;我为什么还要写这篇文章呢&#xff1f; 因为我发现网上 99% 的文章&#xff0c;并没有把这个问题真正…

Java线程安全

前段时间有测试一个后端对账单和话单采集服务,在测试过程中有涉及到数据库读写逻辑和并发的场景,所以结合经验针对系统技术架构设计了部分并发场景结合数据库读写时可能出现的一些问题的用例,也确实出现了一些测试环境容易忽视,线上环境确确实实可能出现的问题,当然最后还是得到…

线程安全之 - ThreadLocal

ThreadLocal的底层原理 ThreadLocal是Java中所提供的线程本地存储机制&#xff08;线程内共享&#xff09;&#xff0c;可以利⽤该机制将数据缓存在某个线程内部&#xff0c; 该线程可以在任意时刻、任意⽅法中获取缓存的数据&#xff1b;ThreadLocal底层是通过ThreadLocalMap…

线程锁(ReentrantLock、synchronized)为何不能用作分布式锁

为什么使用分布式锁 分布式锁实现目前有三种&#xff1a; 数据库乐观锁&#xff1b;ZooKeeper的分布式锁;Redis的分布式锁&#xff1b; 在以前单体架构Web应用场景下&#xff0c;我们可以使用ReentrantLock或synchronized进行上锁&#xff0c;保证资源安全&#xff0c;现如今大…

Redis分布式锁真的安全吗?

大家好&#xff0c;今天我们来聊一聊Redis分布式锁。 首先大家可以先思考一个简单的问题&#xff0c;为什么要使用分布式锁&#xff1f;普通的jvm锁为什么不可以&#xff1f; 这个时候&#xff0c;大家肯定会吧啦吧啦想到一堆&#xff0c;例如java应用属于进程级&#xff0c;…

ThreadLocal能解决线程安全问题?胡扯!本文教你正确的使用姿势【享学Java】

跟对领导很重要&#xff1a;愿意教你的&#xff0c;并且放手让你做的领导要珍惜。 目录 前言正文ThreadLocal是什么&#xff1f;ThreadLocal怎么用&#xff1f;局限性InheritableThreadLocal向子线程传递数据开源框架使用示例 ThreadLocal不能解决共享变量的线程安全问题Thread…

Java线程安全详细总结

以下是我的PPT文档&#xff0c;不知道怎么复制到博客&#xff0c;只能一个一个插入图片发上来了。感觉总结的不错&#xff0c;分享一下。 文档地址&#xff1a;http://download.csdn.net/detail/csujiangyu/9526641

分布式系统详解--基础知识(线程)

分布式系统详解--基础知识&#xff08;线程&#xff09; 一、导读 前面跟大家讲了一下 分布式系统详解--基础知识&#xff08;概论&#xff09; &#xff0c;可以稍微了解一下大体上分布式是怎么一回事了。这片篇文章主要是讲述一下线程的问题分别介绍一下&#xff0c;什么线…

分布式项目线程安全问题(电商扣减库存的安全问题1)

电商减库存存在的安全问题 Override public void deductStock(Map<Long, Integer> skuMap) {for (Map.Entry<Long, Integer> entry : skuMap.entrySet()) {Long skuId entry.getKey();Integer num entry.getValue();// 查询skuSku sku getById(skuId);// 判断…

分布式项目中 如何保证线程安全问题?-------ZooKeeper

前沿&#xff1a; 上篇文章我们聊到了在解决分布式项目中线程安全问题&#xff0c;提到解决方案还有其他的&#xff0c;那么在此提出 基于 zookeeper 解决分布式项目中的线程安全问题 也是目前市面上比较流行的。做为一个高级开发工程师也是必须要学习的。 ZooKeeper是什么东…

分布式线程安全(redis、zookeeper、数据库)

https://blog.csdn.net/u010963948/article/details/79006572 Q:一个业务服务器&#xff0c;一个数据库&#xff0c;操作&#xff1a;查询用户当前余额&#xff0c;扣除当前余额的3%作为手续费 synchronized lock db lock Q&#xff1a;两个业务服务器&#xff0c;一个数据库&…

分布式集群中如何保证线程安全?

目录 分布式集群中的线程安全问题 解决方法 串行化 分布式锁 Redis如何实现呢&#xff1f; 问题&#xff1a;setnx刚好获取到锁&#xff0c;业务逻辑出现异常&#xff0c;导致锁无法释放 问题&#xff1a;可能会释放其他服务器的锁。 问题&#xff1a;删除操作缺乏原子…

java outlook 发送邮件_基于java使用JavaMail发送邮件

一、邮件的相关概念 邮件协议。主要包括&#xff1a; SMTP协议&#xff1a;Simple Mail Transfer Protocol&#xff0c;即简单邮件传输协议&#xff0c;用于发送电子邮件 POP3协议&#xff1a;Post Office Protocol 3&#xff0c;即邮局协议的第三个版本&#xff0c;用于接收邮…

java 发邮件(有正文,有图片,有附件)

一 需求: 1 java实现邮件发送 2 发送内容: ① 正文: 图片说明和图片 ② 附件一: 图片作为附件发送 ③ 附件二: Excel表格 二 思路: 1首先创建一个 Java 工程&#xff0c;把下载好的 javax.mail.jar 作为类库加入工程 2邮件创建步骤: 配置连接邮件服务器的参数( 邮件服务器SM…