【并发编程】volatile的原理我好像又懂了
文章目录
- 优秀引用
- 1、概述
- 2、可见性保证
- 2.1、什么是可见性
- 2.2、例子举证
- 2.3、结果解析
- 3、有序性保证
- 3.1、什么是有序性
- 3.2、什么是重排序
- 3.3、例子举证
- 4、无法保证原子性
- 4.1、什么是原子性
- 4.2、例子举证
- 5、内存屏障
- 5.1、什么是内存屏障
- 5.2、不同内存屏障的作用
- 6、volatile和synchronized的区别
- 7、使用场景
- 7.1、多线程共享变量
- 7.2、双重检查锁定
- 7.3、状态标志
优秀引用
尚硅谷JUC并发编程(对标阿里P6-P7)之volatile
Java中不可或缺的关键字「volatile」
全面理解Java的内存模型(JMM)
1、概述
在多线程编程中,确保线程安全和正确的执行顺序是非常重要的。由于多线程环境下,不同线程之间共享内存资源,因此对这些资源的访问必须进行同步以避免出现竞态条件等问题。Java中提供了多种方式来实现同步,其中 volatile
是一种非常轻量级的同步机制。
volatile
直译过来是“不稳定的”,意味着被其修饰的属性可能随时发生变化。该关键字为Java提供了一个轻量级的同步机制:保证被volatile修饰的共享变量对所有线程总是可见的,也就是当一个线程修改了一个被 volatile
修饰共享变量的值,新值总是可以被其他线程立即得知。相较于我们熟知的重量级锁 synchronized
,volatile
更轻量级,因为它不会引起上下文切换和线程调度。
volatile
关键字的特性主要有以下几点:
- 保证可见性:当一个变量被声明为
volatile
时,所有线程都可以看到它的最新值,即每次读取都是从主内存中获取最新值,而不是从线程的本地缓存中获取旧值; - 保证有序性:
volatile
关键字可以禁止指令重排序。编译器和CPU为了提高代码执行效率,可能会对指令进行重排序,这可能会导致线程安全问题。但是,当一个变量被声明为volatile
时,编译器和CPU会禁止对它进行指令重排序,保证指令执行的正确顺序; - 无法保证原子性:
volatile
关键字并不能保证操作过程中的有序性,如果需要保证一系列操作的原子性,仍然需要借助锁机制进行限制。
2、可见性保证
2.1、什么是可见性
可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他县城能够立即看到修改的值。
2.2、例子举证
我们通过一个循环的例子进行举证,大致是使用一个变量标识一个 while
循环,通过新线程修改这个标识,进而查看循环是否会结束。接下来将会对未加上和加上 volatile
进行举例查看结果。
- 未加
volatile
的普通flag。
public class VolatileSeeTest {static boolean flag = true;public static void main(String[] args) throws InterruptedException {new Thread(() -> {int i = 1;while (flag) {if (i == 1) {System.out.println("掉坑里了……");i = 0;}}System.out.println("我出来啦!.(flag此时为" + flag);}, "t1").start();// 等待确保上面t1线程已经执行Thread.sleep(1000L);flag = false;System.out.println("好小子,速速跳出坑来.(flag此时为" + flag);}
}================================================此时结果打印:
掉坑里了……
好小子,速速跳出坑来.(flag此时为false)
(程序还未结束,代表t1线程还在死循环中)================================================
- 加上
volatile
的flag。
public class VolatileSeeTest {static volatile boolean flag = true;public static void main(String[] args) throws InterruptedException {new Thread(() -> {int i = 1;while (flag) {if (i == 1) {System.out.println("掉坑里了……");i = 0;}}System.out.println("我出来啦!.(flag此时为" + flag);}, "t1").start();// 等待确保上面t1线程已经执行Thread.sleep(1000L);flag = false;System.out.println("好小子,速速跳出坑来.(flag此时为" + flag);}
}================================================掉坑里了……
好小子,速速跳出坑来.(flag此时为false)
我出来啦!.(flag此时为false)Process finished with exit code 0(程序已经结束)================================================
2.3、结果解析
针对于第一种没有 volatile
关键字修饰的情况,很明显 主线程 对 flag 变量的修改对 t1 线程并不可见,导致 t1 线程中的循环并未跳出。这是因为 主线程 和 t1 线程中分别都对 flag 变量进行了拷贝,备份到了各自中的本地缓存(也叫做工作内存或本地内存)中,当两个线程读取 flag 变量时都是从本地缓存中读取,主线程 中对 flag 变量进行的操作对 t1 线程并不可见,导致每次 t1 线程读取 flag 变量时都是初始保存的 false。
根本原因是因为没有
volatile
关键字修饰的变量并没有及时的从主存中读取最新值和往主存中写入自己修改的值,如果其他线程要访问这个变量,它们可能会直接从自己的本地缓存中读取这个变量的值,而不是从主内存中读取,导致在多线程环境下不同线程之间的数据出现不一致情况。
针对于第二种添加了 volatile
关键字修饰的情况,通过结果我们可以看出 t1 线程成功跳出了循环最终程序结束,证明了 volatile
关键字是可以保证可见性的。这是因为被 volatile
修饰的 flag 变量被修改后,JMM 会把该线程本地缓存中的这个 flag 变量立即强制刷新到主内存中去,导致 t1 线程中的 flag 变量缓存无效,也就是说其他线程使用 volatile
修饰的 flag 变量时,都是从主内存刷新的最新数据。
3、有序性保证
3.1、什么是有序性
所谓的有序性,顾名思义就是程序执行的顺序按照指定的顺序先后执行。
3.2、什么是重排序
现代的计算机为了提高性能,在程序运行过程中常常会对指令进行重排序,这就涉及到了为此诞生的 流水线技术。
所谓的 流水线技术,就是指一个CPU指令的执行过程可以分为4个阶段:取指、译码、执行、写回。它的原理是在不影响程序运行结果的情况下,指令1还没有执行完,就可以开始执行指令2,而不用等到指令1执行结束之后再执行指令2,这样就大大提高了效率。
但是在多线程的情况下,指令重排可能会影响本地缓存和主存之间交互的方式,造成乱序问题最终导致数据错乱。指令重排一般可以分为下面三种类型:
- 编译器优化重排。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
- 指令并行重排。现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性(即后一个执行的语句无需依赖前面执行的语句的结果),处理器可以改变语句对应的机器指令的执行顺序。
- 内存系统重排。由于处理器使用缓存和读写缓存冲区,这使得加载(load)和存储(store)操作看上去可能是在乱序执行,因为三级缓存的存在,导致内存与缓存的数据同步存在时间差。
3.3、例子举证
了解过单例模式的小伙伴可能都了解过,双重校验锁有一个volatile版本的:
public class Singleton {// 私有构造方法private Singleton() {}// 使用volatile禁止单例对象创建时的重排序private static volatile Singleton instance;// 对外提供静态方法获取该对象public static Singleton getInstance() {// 第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实际if(instance == null) {synchronized (Singleton.class) {// 抢到锁之后再次判断是否为空if(instance == null) {instance = new Singleton();}}}return instance;}
}
有小伙伴可能会问到不是已经上了锁并且都进行判断了嘛,怎么还会有并发问题,还得加上 volatile
关键字解决的。这就得扯到在多线程环境下对 instant 对象实例化时计算机对其的指令重排了:
当一个线程执行到第一次判空时,由于 instant 还没有被初始化,因此会进入同步块中进行初始化操作。但是,在初始化过程中,由于指令重排序的影响, instant 可能会被先分配空间并赋值,然后再进行构造函数的初始化操作。此时,如果有另外一个线程进入了第一次判空,并且发现 instant 不为 null
,就会直接返回一个尚未完成初始化的实例,从而导致并发问题。
4、无法保证原子性
4.1、什么是原子性
原子性是指一个操作或者一系列操作要么全部执行成功,要么全部不执行,不会出现部分执行的情况。
4.2、例子举证
常见的非原子性操作便是自增操作,因为自增操作在指令层面可以分为三步:
- i 被从局部变量表(内存)取出;
- 压入操作栈(寄存器),操作栈中自增;
- 使用栈顶值更新局部变量表(寄存器更新写入内存)。
我们对 volatile 修饰的变量进行自增操作,通过查看结果来验证这一特性:
public class VolatileAtomicTest {public static volatile int val;public static void add() {for (int i = 0; i < 1000; i++) {val++;}}public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(Test1::add);Thread t2 = new Thread(Test1::add);t1.start();t2.start();// 等待线程运算结束t1.join();t2.join();// 打印结果System.out.println(val);}
}
按照正常情况,最终输出的应该是2000,但是我们运行起来会发现结果并不如意,绝大多数情况下都会低于2000,从而验证了 volatile 并不能保证原子性。这是因为多线程环境下,可能 线程t1 正在进行 第i次
的 取值-运算-赋值 操作时,另外一个 线程t2 已经完成了操作并提交到了主存中,主存就会通知 线程t1 本地缓存中的数据已经过时,从而丢弃手中正在进行的对数据的操作,去获取最新的数据,导致 线程t1 要开始 第i+1次
运算从而浪费了 第i次
的运算机会,导致最终的结果没有达到我们预想的2000。
原子性的保证可以通过 synchronized、Lock、Atomic
5、内存屏障
5.1、什么是内存屏障
内存屏障,也称内存栅栏,是一类同步屏障指令,是CPU或编译器在对内存随机访问的操作中的一个同步点,是的词典之前的所有读写操作都执行后才可以开始执行词典之后的操作,避免代码的重排序。
内存屏障其实就是一种JVM指令,Java内存模型的重排规则会要求Java编译器在生成JVM指令时插入特定的内存屏障指令,通过这些内存屏障指令,volatile实现了Java内存模型中的可见性和有序性。
通过对有 volatile 关键字修饰的变量进行操作的代码进行反编译我们会发现,在 volatile 范围内多了个lock前缀指令,这里简单介绍一下这一指令的作用。
当一个变量被volatile修饰后,它在读写时会使用一种特殊的机器指令(lock前缀指令),这个指令可以保证多个线程在读写这个变量时不会出现问题:
- 写volatile变量时,会先把变量的值写入到CPU缓存中,然后再把缓存中的数据写入到主内存中,这样其他线程就能看到最新的值了。
- 读volatile变量时,会从主内存中读取最新的值,而不是从CPU缓存中读取,这样就能保证不会拿到过期的值了。
此外,由于lock前缀指令会对指定的内存区域加锁,保证了对该变量的读写操作的原子性,避免了出现竞态条件。
5.2、不同内存屏障的作用
对于内存屏障的分类其实分有两种,其中一种常见的便是对内存屏障的粗分:
- 读屏障:用于确保在读取共享变量之前,先要读取该变量之前的所有操作的结果;
- 写屏障:用于确保在写入共享变量之后,后续的所有操作都不能被重排序到写操作之前。
细分之下,内存屏障又分为四种:
- LoadLoad屏障:
- 保证在读取共享变量之前,先要读取该变量之前的所有操作的结果。
- 指令
Load1; LoadLoad; Load2
,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
- LoadStore屏障:
- 保证在读取共享变量之前,先要读取该变量之前的所有操作的结果,并且在写入共享变量之后,后续的所有操作都不能被重排序到写操作之前。
- 指令
Load1; LoadStore; Store2
,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
- StoreStore屏障:
- 保证在写入共享变量之后,后续的所有写操作都不能被重排序到写操作之前。
- 指令
Store1; StoreStore; Store2
,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
- StoreLoad屏障:
- 保证在写入共享变量之后,后续的所有读操作都不能被重排序到写操作之前。
- 指令
Store1; StoreLoad; Load2
,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能
对于volatile操作而言,其操作步骤如下:
- 每个volatile写入之前,插入一个 StoreStore,写入以后插入一个 StoreLoad
- 每个volatile读取之前,插入一个 LoadLoad,读取之后插入一个 LoadStore
6、volatile和synchronized的区别
volatile和synchronized都可以保证多线程之间的可见性和原子性,但是它们之间有以下几点不同:
- volatile只能保证可见性和有序性,不能保证原子性。而synchronized既可以保证可见性和有序性,也可以保证原子性。
- volatile不会阻塞线程,而synchronized会阻塞线程。
- volatile只能修饰变量,而synchronized可以修饰方法和代码块。
- volatile只能保证单次读/写的原子性,不能保证多次读/写的原子性。而synchronized可以保证多次读/写的原子性。
可见性保证 | 原子性保证 | 有序性保证 | 阻塞线程 | 可修饰对象 | 多次操作原子性 | |
---|---|---|---|---|---|---|
volatile(轻量) | ✔️ | ❌ | ❌ | ❌ | 变量 | ❌ |
synchronized(重量) | ✔️ | ✔️ | ✔️ | ✔️ | 方法、代码块 | ✔️ |
7、使用场景
7.1、多线程共享变量
在多线程环境下,多个线程可能同时访问同一个变量。如果这个变量没有被声明为 volatile
,那么每个线程都会从自己的缓存中读取这个变量的值,而不是从主内存中读取。这样就可能会出现一个线程修改了变量的值,但是其他线程并没有及时得到变量的更新,导致程序出现错误。
使用 volatile
声明变量可以保证每个线程都从主内存中读取变量的值,而不是从自己的缓存中读取。这样就可以保证多个线程访问同一个变量时的可见性和正确性。
7.2、双重检查锁定
双重检查锁定(Double-checked locking)是一种延迟初始化的技术,常用于单例模式的实现。在双重检查锁定模式中,首先检查是否已经实例化,如果没有实例化,则进行同步代码块,再次检查是否已经实例化,如果没有则进行实例化。
但是在没有使用volatile修饰共享变量的情况下,可能会出现线程安全问题。因为在实例化对象时,可能会出现指令重排的情况,导致其他线程在检查对象是否为null时,得到的是一个尚未完全初始化的对象。
使用volatile声明共享变量可以禁止指令重排,从而保证双重检查锁定模式的正确性。
7.3、状态标志
当一个变量被用于表示某个状态时,例如线程是否终止、是否可以执行某项操作等,需要使用volatile来保证操作的可见性和正确性。
在多线程环境下,一个线程修改了状态变量的值,其他线程需要及时得到变量的更新,以保证程序的正确性。
相关文章:
【并发编程】volatile的原理我好像又懂了
文章目录优秀引用1、概述2、可见性保证2.1、什么是可见性2.2、例子举证2.3、结果解析3、有序性保证3.1、什么是有序性3.2、什么是重排序3.3、例子举证4、无法保证原子性4.1、什么是原子性4.2、例子举证5、内存屏障5.1、什么是内存屏障5.2、不同内存屏障的作用6、volatile和sync…...
【已更新实例】Java网络爬虫-HttpClient工具类
关于用Java进行爬虫的资料网上实在少之又少,但作为以一名对Java刚刚初窥门径建立好兴趣的学生怎么能静得下心用新学的Python去写,毕竟Java是世界上最好的语言嘛 (狗头)关于Java爬虫最受欢迎的一个框架Jsoup常常搭配HttpClient来使用,因为Jsou…...
7.2 向量的坐标
🙌作者简介:数学与计算机科学学院出身、在职高校高等数学专任教师,分享学习经验、生活、 努力成为像代码一样有逻辑的人! 🌙个人主页:阿芒的主页 ⭐ 高等数学专栏介绍:本专栏系统地梳理高等数学…...
公式编写1000问21-22
21.问: 求助——(周,日,60分钟,30分钟)MACD同时向上的公式怎么表达 答(知无不言): z:“macd.dea#week”; r:“macd.dea#day”; f:“macd.dea#min60”; f1:“macd.dea#min30”; rz:“macd.dea##week”; rr:“macd.dea##day”; rf:“…...
1041 考试座位号
每个 PAT 考生在参加考试时都会被分配两个座位号,一个是试机座位,一个是考试座位。正常情况下,考生在入场时先得到试机座位号码,入座进入试机状态后,系统会显示该考生的考试座位号码,考试时考生需要换到考试…...
2023年3月北京/广州/杭州/深圳数据治理工程师认证DAMA-CDGA/CDGP
DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义,帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力,促进开展工作实践应用及实际问题解决,形成企业所需的新数字经济下的核心职业…...
【AICG】2、扩散模型 | 到底什么是扩散模型?
文章目录一、什么是扩散模型二、扩散模型相关定义2.1 符号和定义2.2 问题规范化三、可以提升的点参考论文:A Survey on Generative Diffusion Model github:https://github.com/chq1155/A-Survey-on-Generative-Diffusion-Model 一、什么是扩散模型 已…...
高等数学——多元函数微分学
文章目录多元函数微分学多元函数的极限多元函数的连续性偏导数定义高阶偏导数全微分定义全微分存在的必要条件全微分存在的充分条件多元函数的微分法复合函数微分法隐函数微分法多元函数的极值与最值无约束极值条件极值及拉格朗日乘数法最大值最小值二重积分概念性质计算利用直…...
一文打通Sleuth+Zipkin 服务链路追踪
1、为什么用 微服务架构是一个分布式架构,它按业务划分服务单元,一个分布式系统往往有很多个服务单元。由于服务单元数量众多,业务的复杂性,如果出现了错误和异常,很难去定位。主要体现在,一个请求可能需要…...
牛客刷题第一弹
1.异常处理 都是Throwable的子类: ①.Exception(异常):是程序本身可以处理的异常。 ②.Error(错误): 是程序无法处理的错误。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,一般不需…...
K8s:通过 Kubeshark 体验 大白鲨(Wireshark)/TCPDump 监控 Kubernetes 集群
写在前面 分享一个 k8s 集群流量查看器很轻量的一个工具,监控方便博文内容涉及: Kubeshark 简单介绍Windows、Linux 下载运行监控DemoKubeshark 特性功能介绍 理解不足小伙伴帮忙指正 对每个人而言,真正的职责只有一个:找到自我。…...
MySQL查询索引原则
文章目录 等值匹配原则最左前缀匹配原则范围查找规则等值匹配+范围查找Order By + limit 优化分组查询优化总结MySQL 是如何帮我们维护非主键索引的等值匹配原则 我们现在已经知道了如果是【主键索引】,在插入数据的时候是根据主键的顺序依次往后排列的,一个数据页不够就会分…...
布谷鸟优化算法C++
#include <iostream> #include <vector> #include <cmath> #include <random> #include <time.h> #include <fstream> #define pi acos(-1) //5只布谷鸟 constexpr int NestNum 40; //pi值 //规定X,Y 的取值范围 constexpr double X_…...
三体到底是啥?用Python跑一遍就明白了
文章目录拉格朗日方程推导方程组微分方程算法化求解画图动图绘制温馨提示,只想看图的画直接跳到最后一节拉格朗日方程 此前所做的一切三体和太阳系的动画,都是基于牛顿力学的,而且直接对微分进行差分化,从而精度非常感人…...
Golang-Hello world
目录 安装 Go(如果尚未安装) 编写Hello world 使用Golang的外部包 自动下载需要的外部包...
this指针C++
🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章 🔥座右铭:“不要等到什么都没有了,才下定决心去做” …...
SpringBoot+WebSocket实时监控异常
# 写在前面此异常非彼异常,标题所说的异常是业务上的异常。最近做了一个需求,消防的设备巡检,如果巡检发现异常,通过手机端提交,后台的实时监控页面实时获取到该设备的信息及位置,然后安排员工去处理。因为…...
Baumer工业相机堡盟相机如何使用自动曝光功能(自动曝光优点和行业应用)(C++)
项目场景 Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具…...
HTML、CSS学习笔记7(移动适配:rem、less)
一、移动适配 rem:目前多数企业在用的解决方案vw / vh:未来的解决方案 1.rem(单位) 1.1使用rem单位设置尺寸 px单位或百分比布局可以实现吗? ————不可以 网页的根字号——HTML标签 1.2.rem移动适配 写法&#x…...
STM32感应开关盖垃圾桶
目录 项目需求 项目框图 编辑 硬件清单 sg90舵机介绍及实战 sg90舵机介绍 角度控制 SG90舵机编程实现 超声波传感器介绍及实战 超声波传感器介绍 超声波编程实战 项目设计及实现 项目需求 检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖…...
进程跟线程的区别
进程跟线程的区别 文章目录进程跟线程的区别前言一.什么线程二.线程与进程的联系三.线程与进程有什么不同前言 现代所有计算机都能同时做几件事情,当一个用户程序正在运行时,计算机还能同时读取磁盘,并向屏幕打印输出正文.在一个多道操作程序中,cpu由一道程序向另外一道程的切…...
[ICLR 2016] Unsupervised representation learning with DCGANs
目录 IntroductionModel ArchitectureReferencesIntroduction 作者提出了用 CNN 搭建 GAN,使得 GAN 训练更加稳定的一系列准则,并将满足这些设计理念的模型称为 DCGANs (Deep Convolutional GANs). 此外,作者将 trained discriminators 用于图像分类任务,相比于其他无监督算…...
QT编程从入门到精通之十五:“第五章:Qt GUI应用程序设计”之“5.1 UI文件设计与运行机制”之“5.1.2 项目管理文件”
目录 第五章:Qt GUI应用程序设计 5.1 UI文件设计与运行机制 5.1.2 项目管理文件 第五章:Qt GUI应用程序设计 在“Qt 程序创建基础”上,本章将继续深入地介绍Qt Creator设计GUI应用程序的方法...
基于Three.js和MindAR实现的网页端WebAR人脸识别追踪功能的京剧换脸Demo(含源码)
前言 近段时间一直在玩MindAR的功能,之前一直在弄图片识别追踪的功能,发现其强大的功能还有脸部识别和追踪的功能,就基于其面部网格的例子修改了一个国粹京剧的换脸程序。如果你不了解MindAR的环境配置可以先参考这篇文章:基于Mi…...
动态规划思路
拉勾教育版权所有:https://kaiwu.lagou.com/course/courseInfo.htm?courseId3 动态规划思路 1.最优子结构 2.重复计算子机构 3.依靠递归,层层向上传值,所以编程时初始化子结构很重要 动态规划步骤 1.判断动态规划的类型 1.线性规划 >&…...
HTTPS关键词语解释和简单通讯流程
1、 什么是HTTPS HTTPS是基于HTTP的上层添加了一个叫做TLS的安全层,对数据的加密等操作都是在这个安全层中进行处理的,其底层还是应用的HTTP。 2、 什么是对称加密; 加密和解密都是用同一个秘钥 3、 什么是非对称加密; 加密和…...
“前端开发中的三种定时任务及其应用“
前端定时任务是指在一定时间间隔内,自动执行指定的操作或函数。在前端开发中,定时任务被广泛应用于诸如数据更新、定时提醒、定时刷新页面等方面。在本文中,我们将介绍前端中常见的三种定时任务,分别是 setTimeout、setInterval 和…...
华为OD机试题 - 猜字谜(JavaScript)| 机考必刷
更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:猜字谜题目输入输出描述备注示例一输入输出示例二输入输出思路C…...
python@pyside样式化
文章目录refWidget类创建样式化文件qss引用样式并启动应用ref Styling the Widgets Application - Qt for PythonQt Style Sheets Reference | Qt Widgets 5.15.12 Widget类创建 创建一个简单界面(菜单主要内容)它们是水平布局 主要内容包括一段文本和一个按钮,它们是垂直布…...
C++经典15道面试题目(文末含大题)
今天给大家找了几个C面试里很有可能被问的哦,赶紧收藏下来去背!!! 目录 1)C中有malloc/free,为什么还需要new/delete? 2)C中explicit关键字的作用? 3)C中static关键字的作用&a…...
凡科做的网站被举报了会怎么样/yande搜索引擎官网入口
权限问题 进入我的电脑-上方工具菜单-文件夹选项-查看,取消下方的“使用简单的文件共享”的勾选。选择那个分区的图标-右键-属性-安全,点下方的高级按纽-点上方的所有者标签,选择你的用户名(如果没有那么点添加按纽,如…...
dw制作一个手机网站模板下载/东莞做网站哪家公司好
文章目录函数皆对象函数与闭包博文配套视频课程:24小时实现从零到AI人工智能 函数皆对象 py 一切皆为对象,数据、函数、后续声明的类也是一个对象,而函数名称就是对象名称 def hello(namepython):print(name: , name)# 函数名就是变量名称 gr…...
wordpress拼音目录/南宁seo排名外包
最近在研究邮箱监控,通过邮箱地址、用户名、密码、pop端口获取邮箱内容及附件,将内容和附件保存至本地文件夹中,把当前文件夹打包为zip包上传至文件服务器。 思路: 1.通过邮箱地址、用户名、密码、pop端口(pop3端口号默…...
建设银行网站功能介绍/seo技术培训东莞
IOS开发中 如果只想允许用户竖屏显示界面,只需要在Info.plist文件中,打开Supported interface orientation选项 然后只保留Portrait,其它(绿色箭头总会)的都删除就可以了。 转载于:https://www.cnblogs.com/vincent-gu…...
毕业设计开发网站要怎么做/培训学校
点击上方“程序IT圈”,选择“置顶公众号”工作日早晨7点半,准点开车打卡作者 | 黎明本文经授权转自燃财经(ID:rancaijing)长期被唱衰的百度,终于到了正式告别BAT的关键时刻。过去30天,受业绩下滑和高管离职…...
宿州做网站/seo如何优化网站
欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:段石石 前言 前段时间,因为项目需求, 开始接触了NLP,有感自己不是科班出身,很多东西理解不深,于是花时间再读了一些NLP的经典教程的部分章节…...