牛客模拟面试--001

说一说什么是大端、小端,如何判断大端和小端

答案:
1、字节序
字节顺序,又称端序或尾序(英语:Endianness)。在计算机科学")领域中,是跨越多字节的程序对象的存储规则。
在几乎所有的机器上,多字节对象都被存储为连续的字节序列。例如在C语言中,一个类型为int的变量x地址为0x100,那么其对应地址表达式&x的值为0x100。且x的四个字节将被存储在存储器的0x100, 0x101, 0x102, 0x103位置。

2、大小端
在计算机中一般讲字节序分为两类:Big-Endian(大端字节序) 和Little-Endian。
a) Little-Endian 高位字节在前,低位字节在后。
b) Big-Endian 低位字节在前,高位字节在后。
c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

说一说你对volatile关键字的理解

volatile用于保证内存的可见性,可以将其看做是轻量级的锁,它具有如下的内存语义:

· 写内存语义:当写一个volatile变量时,JMM会把该线程本地内存中的共享变量的值刷新到主内存中。

· 读内存语义:当读一个volatile变量时,JMM会把该线程本地内存置为无效,使其从主内存中读取共享变量。
其中,JMM是指Java内存模型,而本地内存只是JMM的一个抽象概念,它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化。在本文中,大家可以将其简单理解为缓存。
volatile只能保证单个变量读写的原子性,而锁则可以保证对整个临界区的代码执行具有原子性。所以,在功能上锁比volatile更强大,在可伸缩性和性能上volatile更优优势。

加分回答
volatile的底层是采用内存屏障来实现的,就是在编译器生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。内存屏障就是一段与平台相关的代码,Java中的内存屏障代码都在Unsafe类中定义,共包含三个方法:LoadFence()、storeFence()、fullFence()。

【延伸阅读】
可见性是指一个线程对共享变量的修改,另外一个线程能够立刻看到。可见性问题是由CPU缓存导致的,每核CPU均有各自的缓存,这些缓存均要与内存进行同步。例如,线程A要修改内存中变量X,它需要先将变量X加载到本地缓存,修改缓存后再将缓存数据刷回内存中。在线程A修改本地缓存中变量X时,线程B可能也需要读/写内存中的变量X,为了让线程A的修改对线程B感知到,就可以在变量X前加上volatile来解决。

在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序。重排序不会影响单线程的执行结果,但是在并发的情况下,可能会出现诡异的BUG。例如,instance = new Singleton(); 这行代码在执行时,会产生3条字节码指令,而这三条指令的顺序就可能会被编译器重排。CPU在执行指令时
在这里插入图片描述
会保证每条指令的原子性,但是不会保证这三条指令是原子的。所以在三条指令执行期间可能会出现CPU轮换的情况,BUG就可能在这种情况下产生了。
在这里插入图片描述

说一说NIO的实现原理

NIO是基于IO多路复用模型的实现,它包含三个核心组件,分别是Buffer、Channel、Selector。

  1. NIO是面向缓冲区的,在NIO中所有的数据都是通过缓冲区处理的。Buffer就是缓冲区对象,无论读取还是写入,数据都是先进入Buffer的。Buffer的本质是一个数组,通常它是一个字节数组,也可以是其他类型的数组。Buffer是一个接口,它的实现类有ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。

  2. Channel是一个通道,可以通过它读取和写入数据。与流不同的是,流是单向的,而Channel是双向的。数据可以通过Channel读到Buffer里,也可以通过Channel写入到Buffer里。为了支持不同的设备,Channel接口有好几种子类,如FileChannel用于访问磁盘文件、SocketChannel和ServerSocketChannel用于TCP协议的网络通信、DatagramChannel用于UDP协议的网络通信。

  3. Selector是多路复用器,可以通过它监听网络IO的状态。它可以不断轮询注册的Channel,如果某Channel上有连接、读取、写入事件发生,则这个Channel就处于就绪状态,就会被Selector轮询出来。所有被轮询出来的Channel集合,我们可以通过SelectionKey获取到,然后进行后续的IO操作。
    加分回答
    Buffer对象包含三个重要的属性,分别是capacity、position、limit。其中,capacity代表Buffer的容量,就是说Buffer中最多只能写入capacity个数据。position代表访问的位置,它的初始值为0,每读取/写入一个数据,它就会向后移动一个位置。limit代表访问限制,就是本次操作最多能读取/写入多少个数据。这三个属性的关系是,position<=limit<=capacity,Buffer通过不断调整position和limit的值,使得自身可以不断复用。
    【延伸阅读】
    Java NIO根据操作系统的不同,会对Selector做不同的实现。如Linux上的PollSelectorProvider、Windows上的WindowsSelectorProvider、MacOS上的KQueueSelectorProvider等。在使用Selector时,我们不需要指定哪一个实现,JDK会自动选择合适的Selector实现。

请描述Spring Boot自动装配的过程

给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则返回"-1"。目前给出的数据,仅仅会存在一个最长的公共子序列

数据范围:0<=|str1|,|str2|<=2000
要求:空间复杂度O(N2) ,时间复杂度 O(N2)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值