面试官:你说一下对Java中的volatile的理解吧!

内存屏障(Memory Barrier)(一)什么是写屏障? 目录为什么要有写屏障1、Store Buffer提升MESI性能2、Store Buffer导致读写乱序3、写屏障总结 关于内存屏障,我翻阅了很多文章,都没有给人讲的比较明白,因为我看了许多文章之后,仍然有以下几个疑问: 为什么要有内存屏障? 什么是LoadLoad,LoadStore,StoreStore,StoreLoad?他们之间的区别到底是什么? Load和Store有什么不同? 为什么要加Load和Store? 带着这样的疑问,在这一系列文章中,我想从原理开始一点一点说清楚。 为什么要有写屏障 阅读详情

前言

volatile相关的知识其实自己一直都是有掌握的,能大概讲出一些知识,例如:它可以保证可见性;禁止指令重排。这两个特性张口就来,但要再往深了问,具体是如何实现这两个特性的,以及在什么场景下使用volatile,为什么不直接用synchronized这种深入和扩展相关的问题,就回答的不好了。因为volatile是 面试必问知识,所以这次准备把这部分知识也给啃掉。

 

系统处理效率与Java内存模型

在计算机中,每条程序指令都是在CPU中执行的,而CPU执行指令的数据都是临时存储在内存中的,但是CPU的执行速度远超内存的读取速度,如果所有的CPU指令都是通过内存来读取数据的话那么将大大的降低了系统的处理效率,所以现代计算机系统都不得不加入一层或多层读写速度尽可能接近处理器运算速度的高速缓存(Cache)来作为内存与处理器之间的缓冲。

将运算需要使用的数据复制到缓存中,让运算能快速进行,当运算结束后,在从缓存同步回内存之中,这样处理器就无须等待缓慢的内存读写了。

虽然说增加了高速缓存提高了CPU的处理效率,但是也带来了新的问题 :

现代计算机都是多核CPU,一开始,内存中的变量A的值是1,第一个CPU读取了数据,第二个CPU也将数据读取到了自己的高速缓存当中,当第一个CPU对变量A进行加1操作时,变量A的值变成了2,然后将将变量A的值写回内存中,这时第二个CPU也对变量A进行加1操作时,由于第二个CPU中高速缓存中的值还是1,所以加1操作后的结果为2,然后第二个CPU又将变量A的值同步回内存中,这样就导致执行了两次加1操作后,变量A的值最终是2,而不是3。
这种被多个CPU访问的变量,通常称为共享变量。
而产生的上面的问题,就是引入了高速缓存后的,主内存和缓存内容不一致的问题。
因为每个处理器有自己的高速缓存,但是它们又共享同一块主内存,所以必然会出现主内存不知该以哪个高速缓存中的变量为准的情况。

在这里插入图片描述

 

上面这个缓存不一致的问题,我们先记下来,继续来看Java内存模型,其实Java内存模型描述的上面讲的计算机系统高速缓存和内存之间的关系类似。

Java内存模型描述了,各种变量的访问规则,以及将变量存储到内存和从内存读取变量的这种底层细节。

在Java内存模型中关注的变量都是共享变量(实例变量、类变量)。
所有的共享变量都是存储在主内存中的,但是每个线程在访问变量的时候也都会在自己的工作内存(处理器高速缓存)中保留一份共享变量的副本。

Java内存模型(Java Memory Model,简称JMM)规定:

线程对变量的所有操作(读,写)都必须在工作内存中进行,不能直接操作主内存中的数据。
不同线程之间 也不能直接访问对方工作内存中的变量,线程间的变量值传递必须通过主内存进行中转传递。
在JMM中工作内存和主内存的关系如下图:

 

在这里插入图片描述

Volatile的可见性(保证立即可见)

继续我们上面的缓存一致性的问题,这个问题,在Java内存模型中,就是可见性的问题,即一个线程修改了共享变量的值,对另一个线程来说是不是立即可见的。如果不是立即可见的,那么就会出现缓存一致性的问题,如果是立即可见的,那么另一个线程在进行操作的时候,拿到的变量值就是最新的。就可以解决可见性的问题。

那么怎么解决可见性问题呢?

  • 方案一:加锁

将共享变量加锁,无论是synchronized还是Lock都可以,加锁达到的目的是在同一时间内只能有一个线程能对共享变量进行操作,就是说,共享变量从读取到工作内存到更新值后,同步回主内存的过程中,其他线程是操作不了这个变量的。这样自然就解决了可见性的问题了,但是这样的效率比较低,操作不了共享变量的线程就只能阻塞。

  • 方案二:volatile修饰修饰共享变量

当一个共享变量被volatile修饰后,会保证每个线程将变量修改后的值立即同步回主内存中,当其他线程有需要读取变量时会读取到最新的变量值。

那么volatile做了些什么操作就能解决可见性的问题呢?

被volatile修饰的变量,在被线程操作时,会有这样的机制:

就是线程对变量操作时会从主内存中读取到自己的工作内存中,当线程对变量进行了修改后,那么其他已经读取了此变量的线程中的变量副本就会失效,这样其他线程在使用变量的时候,发现已经失效,那么就会去主内存中重新获取,这样获取到的就只最新的值了。

那么volatile这个关键字是如何实现这套机制的呢?

因为一台计算机有多台CPU,同一个变量,在多个CPU中缓存的值有可能不一样,那么以谁缓存的值为准呢?

既然大家都有自己的值,那么各个CPU间就产生了一种协议,来保证按照一定的规律为准,来确定共享变量的准确值,这样各个CPU在读写共享变量时都按照协议来操作。

这就是缓存一致性协议。

最著名的缓存一致性协议就是Intel的MESI了,说MESI时,先解释一下,缓存行:

缓存行(cache line):CPU高速缓存的中可以分配的最小存储单位,高速缓存中的变量都是存在缓存行中的。

MESI的核心思想就是,当CPU对变量进行写操作时发现,变量是共享变量,那么就会通知其他CPU中将该变量的缓存行设置为无效状态。当其他CPU在操作变量时发现此变量在的缓存行已经无效,那么就会去主内存中重新读取最新的变量。

  • 那么其他CPU是如何发现变量被修改了的呢?

因为CPU和其他部件的进行通信是通过总线来进行的,所以每个CPU通过嗅探总线上的传播数据,来检查自己缓存的值是不是过期了,当处理器发现自己换成行对应的内存地址被修改后,就会将自己工作内存中的缓存行设置成无效状态,当CPU对此变量进行修改时会重新从系统主内存中读取变量。

在这里插入图片描述

Volatile的有序性(禁止指令重排)

一般来说,我们写程序的时候,都是要把先代码从上往下写,默认的认为程序是自顶向下顺序执行的,但是CPU为了提高效率,在保证最终结果准确的情况下,是会对指令进行重新排序的。就是说写在前的代码不一定先执行,在后面的也不一定晚执行。

举个例子:

int a = 5; // 代码1
int b = 8; // 代码2
a = a + 4;  // 代码3
int c = a + b;  // 代码4

上面四行代码的执行顺序有可能是

在这里插入图片描述

JMM在是允许指令重排序的,在保证最后结果正确的情况下,处理器可以尽情的发挥,提高执行效率。

当多个线程执行代码的时候重排序的情况就更为突出了,各个CPU为了提高自己的效率,有可能会产生竞争情况,这样就有可能导致最终执行的正确性。

所以为了保证在多个线程下最终执行的正确性,将变量用volatile进行修饰,这样就会达到禁止指令重排序的效果(其实也可以通过加锁,还有一些其他已知规则来实现禁止指令重排序,但是我们这里只讨论volatile的实现方式)。

那么volatile是如何实现指令重排序的呢?

答案是:内存屏障

整理了一份Java面试宝典完整版PDF,已整理成文档

内存屏障是一组CPU指令,用于实现对内存操作的顺序限制。
Java编译器,会在生成指令系列时,在适当的位置会插入内存屏障来禁止处理器对指令的重新排序。

volatile会在变量写操作的前后加入两个内存屏障,来保证前面的写指令和后面的读指令是有序的。

在这里插入图片描述

volatile在变量的读操作后面插入两个指令,禁止后面的读指令和写指令重排序。

在这里插入图片描述

有序性,不仅只有volatile能保证,其他的实现方式也能保证,但是如果每一种实现方式都要了解那对于开发人员来说就比较困难了。

所以从JDK5就出现了happen-before原则,也叫先行发生原则。
先行发生原则总结起来就是:如果一个操作A的产生的影响能被另一个操作B观察到,那么可以说,这个操作A先行发生与操作B。

这里所说的影响包括内存中的变量的修改,调用了方法,发送量消息等。

volatile中的先行发生原则是,对一个volatile变量的写操作,先行发生于后面任何地方对这个变量的读操作。

Volatile无法保证原子性

原子性,是指一个操作过程要么都成功,要么都失败,是一个独立的完整的。

就像上面说的,如果多个线程对一个变量进行累加,那么肯定得不到想要的结果,因为累加就不是一个原子操作。

要保证累加最终结果正确,要么对累加变量加锁,要么就用AotomicInteger这样的变量。

/**
 * 双重检查加锁式单例
 */
public class DoubleCheckLockSingleton implements Serializable{

    /**
     * 静态变量,用来存放实例。
     */
    private volatile static DoubleCheckLockSingleton doubleCheckLockSingleton = null;

    /**
     * 私有化构造方法,禁止外部创建实例。
     */
    private DoubleCheckLockSingleton(){}

    /**
     * 双重检查加锁的方式保证线程安全又能获得到唯一实例
     * @return
     */
    public static DoubleCheckLockSingleton getInstance(){
        //第一次检查实例是否已经存在,不存在则进入代码块
        if(null == doubleCheckLockSingleton){
            synchronized (DoubleCheckLockSingleton.class){
                //第二次检查
                if(null==doubleCheckLockSingleton){
                    doubleCheckLockSingleton = new DoubleCheckLockSingleton();
                }
            }
        }

        return doubleCheckLockSingleton;
    }

}

为什么要进行双重检查呢?
当第一个线程走到第一次检查时发现对象为空,然后进入锁,第二次就检查时也为空,那么就去创建对象,但是这个时候又来了一个线程来到了第一次检查,发现为空,但是这个时候因为锁被占用,所以就只能阻塞等待,然后第一个线程创建对象成功了,由于对象是被volatile修饰的能够立即反馈到其他线程上,所以在第一个线程释放锁之后,第二个线程进入了锁,然后进行第二次检查时,发现对象已经被创建了,那么就不在创建对象了。从而保证的单例。

还有就是如果创建对象,步骤:

  1. 分配内存空间。
  2. 调用构造器,实例化。
  3. 返回内存地址给引用。

如果这三个指令顺序被重排了,那么当多线程来获取对象的时候就会造成对象虽然实例化了,但是没有分配内存空间,会有空指针的风险。
所以加上了volatile的对象,也保证了在第二次检查时不会被已经在创建过程中的对象有被检测为空的风险。

总结一下

volatile其实可以看作是轻量级的synchronized,虽然说volatile不能保证原子性,但是如果在多线程下的操作本身就是原子性操作(例如赋值操作),那么使用volatile会由于synchronized。

volatile可以适用于,某个标识flag,一旦被修改了就需要被其他线程立即可见的情况。也可以修饰作为触发器的变量,一旦变量被任何一个线程修改了,就去触发执行某个操作。

volatile的变量写操作happen-before,后面任何对此volatile变量的读操作。

面试官:“volatile 你用过吗?” 我一紧张,说错了! 适用场景变量可见性问题防止指令重排(比如 DCL)状态标志位不适用场景不能保证原子性(i++ 仍然需要 AtomicInteger 或 synchronized) 阅读详情

相关推荐

Synchronized、volatile与ReentrantLock:Java并发编程中的同步机制比较

在Java并发编程中,确保多个线程安全地访问共享资源是至关重要的一环。Synchronized、volatile与ReentrantLock是三种常用的同步机制,它们各有特点和应用场景。下面从技术难点、面试官关注点以及回答吸引力三个方面详细比较这三种机制。

2401_84909321的博客 1530

Chrome 出现内存 不足

地址栏直接输入:chrome://flags/#automatic-tab-discarding这里默认default 改为Enable即可为了麻烦 不想每次 都输入网址改 或者认为Chrome 幺儿不听话了 直接来个快捷方式在Chrome中用Ctrl+d 建立一个书签 把上面网址复制到对应位置 保存起来即可...

主攻大数据 人工智能 物联网 安全 低空经济等方向。mtsc 、gtest特邀分享嘉宾 2万+

【JVM】三色标记法与读写屏障

关于垃圾回收算法,基本就是那么几种:标记-清除、标记-复制、标记-整理。在此基础上可以增加分代(新生代/老年代),每代采取不同的回收算法,以提高整体的分配和回收效率。无论使用哪种算法,标记总是必要的一步。这是理算当然的,你不先找到垃圾,怎么进行回收?标记出哪些对象是存活的,哪些是垃圾(可回收);进行回收(清除/复制/整理),如果有移动过对象(复制/整理),还需要更新引用。本文着重来看下标记的部分。

九师兄 7113

没有足够的内存继续执行程序。 (mscorlib)

在执行sql脚本语言时,提示如下错误: 解决方法: Win+R 键入:cmd 命令,开启命令行工具;输入:sqlcmd -S . -U sa -P 123 -i F:\123.sql 。 参数说明:-S 服务器地址(.或127.0.0.1) -U 用户名(sa) -P 密码(123) -i sql脚本文件路径 (F:\123.sql) 如果要指定数据库的,则命令如下: sqlcmd -S . -U sa -P 123 -d demo -i F:\123.sql 参数说明:-S 服务...

weixin_44538156的博客 2575

【异常】IDEA提示没有足够的内存来执行请求的操作

收到“没有足够的内存来执行请求的操作,请增加’Xmx’设置并重启IDE以使更改生效”这类错误信息。

奶爸的编程之路,也就一周冷个三天 2201

面试官:volatile关键字用过吧?说一下作用和实现吧

极简计算机发展史 我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区。而刚开始用户磁盘和CPU进行交互,CPU运转速度越来越快,磁盘远远跟不上CPU的读写速度,才设计了内存,但是随着CPU的发展,内存的读写速度也远远跟不上CPU的读写速度,因此,为了解决这一纠纷,CPU厂商在每颗CPU上加入了高速缓存,用来缓解这种症状,因此,现在CPU同内存交互就变成了下面的样子。 单核CPU的性能不可能无限制的增长,要想很多的提升新能,需要多个处理器协同工作。 基于高速缓存的存储交互很好的解决了处理.

小识的博客 5989

java中aotomicInteger_面试官:你说一下对Java中的volatile的理解吧!

前言volatile相关的知识其实自己一直都是有掌握的,能大概讲出一些知识,例如:它可以保证可见性;禁止指令重排。这两个特性张口就来,但要再往深了问,具体是如何实现这两个特性的,以及在什么场景下使用volatile,为什么不直接用synchronized这种深入和扩展相关的问题,就回答的不好了。因为volatile是面试必问知识,所以这次准备把这部分知识也给啃掉。系统处理效率与Java内存模型...

weixin_39836726的博客 76

【Java并发编程】10. 一文搞懂volatile 由浅入深,直击痛点

今天闲来无事跟同事小麦大叔闲聊, SoWhat:麦叔听说你偷偷面阿里啦,面的咋样? 小麦大叔: 一面挺简单的,主要问了一些基本的数据结构跟算法,还问了下 HashMap的十大常见基本问题。我都答案上来了,还问了我JDK7环,幸亏你那个HashMap环绘制的牛逼,我答的不错就让我准备二面了。 SoWhat:二面类? 小麦大叔:二面问了我一些JVM的问题,问我对于JVM内存模型的理解,还有GC的常见...

sowhat 1万+

【面试官:说一下volatile】

例如,在对一个volatile变量进行写操作时,Java 会在写操作之后插入一个写屏障,以确保前面的写操作对其他处理器可见,然后再插入一个读屏障,以防止后面的读操作重排序到写操作之前。例如:在一个线程中修改了一个 volatile 变量的值,这个修改会立即刷新到内存中,并且其他线程在读取这个变量时,会从主内存中获取最新的值,而不是使用自己工作内存中的缓存值。在一个线程中,对变量 A 的写操作必须在对变量 B 的写操作之前完成,插入一个内存屏障可以确保这种顺序在多线程环境下也能得到保证。

C384136844的博客 952

Apache NiFi新手必看:从零开始的数据流设计入门教程(含实战案例)

本文为Apache NiFi新手提供从零开始的数据流设计入门指南。通过实战案例,详细讲解了如何利用这一强大的数据采集工具,以可视化拖拽方式构建自动化数据流,实现从文件监控、内容处理到数据入库的全流程,并涵盖核心概念、环境搭建及生产环境调优要点。

weixin_29066781的博客 149

用SOEM库搞定汇川SV660N伺服电机:一个Linux C程序员的EtherCAT实战笔记

本文详细介绍了如何在Linux系统下使用SOEM库驱动汇川SV660N伺服电机,包括环境搭建、EtherCAT从站设备识别、PDO映射配置、状态机切换与运动控制等关键步骤。通过实战代码示例和常见问题排查指南,帮助开发者快速掌握工业自动化中的EtherCAT通信技术,实现对伺服电机的精准控制。

weixin_29185199的博客 424

反制面试官 | 14张原理图 | 再也不怕被问 volatile!

反制面试官 | 14张原理图 | 再也不怕被问 volatile! 悟空 爱学习的程序猿,自主开发了Java学习平台、PMP刷题小程序。目前主修Java、多线程、SpringBoot、SpringCloud、k8s。本公众号不限于分享技术,也会分享工具的使用、人生感悟、读书总结。 絮叨 这一篇也算是Java并发编程的开篇,看了很多资料,但是轮到自己去整理去总结的时候,发现还是要多看几遍资料才能完全理解。还有一个很重要的点就是,画图是加深印象和检验自己是否理解的一个非常好的方法。 一、Volati

悟空聊架构的专栏 1118

低功耗模式下的看门狗使用

最近用国产芯片AT32在做一个低功耗的项目,为了实现低功耗模式下的定时唤醒,我选择的是使用相对比较简单的看门狗来做,下面就分享一下使用过程~ 为了最大限度的降低功耗,我用的是待机模式,先看看几种低功耗模式以及唤醒的区别: 而看门狗AT32提供了两种,分别是独立看门狗(IWDG)和窗口看门狗(WWDG),其区别大概有以下几点: 1、独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效;窗口看门狗由从 APB1 时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常

dc18883988396的博客 3028

Java面试官最爱问的volatile关键字

该问题涉及到Java内存模型(JVM)和它的内存可见性特性,这里将前面系列《Java内存模型(JMM)详解》和《Java内存模型相关原则详解》中的部分内容整理出来回答。Java虚拟机规范试图定义一种Java内存模型(JMM),来屏蔽掉各种硬件和操作系统的内存访问差异,让Java程序在各种平台上都能达到一致的内存访问效果。Java内存模型是通过变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值,将主内存作为传递媒介。可举例说明内存可见性的过程。。。而普通变量不能够保证。...

m0_67392126的博客 156

用C#语言实现记事本

本次程序设计作业为用C#语言设计一个记事本,设计的记事本应与电脑系统自带的记事本类似,最后实现的界面及功能应类似于下图。

qq_57738695的博客 2847

手把手教你用LTspice仿真BUCK-BOOST电路(附波形分析)

本文详细介绍了如何使用LTspice进行BUCK-BOOST电路的仿真与波形分析,涵盖电路原理、CCM与DCM模式特性、效率优化及常见问题解决方案。通过实战案例,帮助工程师快速掌握升降压转换电路的设计与调试技巧,提升电力电子设计能力。

julia4scientist的博客 1048

Java面试官最爱的volatile关键字

在Java相关的岗位面试中,很多面试官都喜欢考察面试者对Java并发的了解程度,而以volatile关键字作为一个小的切入点,往往可以一问到底,把Java内存模型(JMM),Java并发编程的一些特性都牵扯出来,深入地话还可以考察JVM底层实现以及操作系统的相关知识。 下面我们以一次假想的面试过程,来深入了解下volitile关键字吧! 面试官: Java并发这块了解的怎么样?说说你对v...

qq_34928026的博客 178

高通SA8155P车载Camera开发避坑指南:从硬件拓扑到AIS服务调试全流程

本文详细解析了高通SA8155P车载Camera开发全流程,从硬件拓扑设计到AIS(Automotive Imaging System)服务调试,涵盖关键组件配置、软件架构剖析及高级调试技巧。通过实战经验分享,帮助开发者避开常见陷阱,优化系统性能,适用于智能驾驶系统的环境感知开发。

weixin_42550597的博客 331

请谈谈你对volatile的理解?--最近小李子与面试官的一场“硬核较量”

JAVA面试时,经常问到Volatile关键字。下面将对其进行研究: 1. 请谈谈你对volatile的理解 1.volatile是Java虚拟机提供的轻量级的同步机制 1.1保证可见性 1.2不保证原子性 1.3禁止指令重排 2.JMM你谈谈 JMM(Java内存模型Java Memory Model,简称JMM)本身是一种抽象的概念 并不真实存在,它描述的是一组 规则或规范通过规范定制了程序中各个变量

认知 行动 坚持 2791

【Codecs系列】x265编码器(十二):子像素运动搜索

在基于块运动补偿的视频编码框架中,运动搜索是最为重要的环节之一,同时也是编码端最为耗时的模块。运动搜索包括整像素运动搜索和子像素运动搜索,其中整像素运动搜索已经有很多快速算法,比如经典的三步搜索法、菱形搜索、六边形搜索以及TZSearch等等;但子像素搜索的快速算法却比较少,本文主要讲解x265编码器中的子像素搜索方法以及相关的快速搜索方法。

优快云明星博主,认证博客专家,视频、Matlab领域优质创作者。 749

计算数列位置N的值

本文介绍了一个数列生成问题,要求根据输入的两个整数M和N生成特定规则的数列,并输出第N个位置上的数值。数列生成规则为:前M个元素为1到M;后续元素根据前M个元素是否重复来决定计算方式(求和或求差)。文章提供了C++、Java和Python三种语言的实现方案,均包含输入处理、数列初始化、循环计算和结果输出等步骤。各语言实现中均使用集合去重特性判断重复元素,并通过内置函数或自定义方法求取最大值和最小值。该问题主要考察基础编程能力,包括数组/列表操作、最值计算和重复元素判断等基本编程技巧。

面试高手的博客 655

面试官:谈谈你对 Volatile 的理解吧

前言 在之前的文章 深入分析 Synchronized 原理 介绍了 Synchronized是一种锁的机制,存在阻塞和性能的问题,而 volatile 是 java 虚拟机提供的最轻量级的同步机制,volatile 主要提供修饰共享变量赋予 “可见性” 和 “有序性”。从简单的 Demo 引出我们今天的主题 -- volatile。 Demo -- 多线程共享对象 控制执行开关。 public class Demo { private static boolean switchStat..

HongYu012的博客 263

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

面试大杀器之:给我说说:volatile

原因就是flag初始的时候,初始值会加载进主内存,再由主内存写进本地内存,线程A执行时就会一直读本地内存,尽管线程B抢占了线程,将主内存的flag赋值未false,但是线程A由于执行太快,并不会在执行之前将主内存的值实时更新进线程A的本地内存。种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果,JMM规范了Java虚拟机与计算机内存是如何协同工作的:规定了一个线程如何和何时可以看到由其他线程修改过后的共享变量的值,以及在必须时如何同步的访问共享变量。

lovestelydsd的博客 402

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

面试官最爱的volatile关键字

Linux编程点击右侧关注,免费入门到精通!作者丨卡巴拉的树juejin.im/post/5a2b53b7f265da432a7b821c在Java相关的岗位面试中,很多...

<sdffdsfsdfdfs>sfsfsfsdfsdffds</sdfsDS>Fsd 949

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

上一篇: 2020最后一次Java面试,快手三面一轮游,如今已拿意向书!
下一篇: 面试官突击一问:你来讲讲AQS是什么吧?都是怎么用的?
加班不秃顶
博客等级 码龄7年 1822粉丝 599原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值