说一说什么是大端、小端,如何判断大端和小端
答案:
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。
-
NIO是面向缓冲区的,在NIO中所有的数据都是通过缓冲区处理的。Buffer就是缓冲区对象,无论读取还是写入,数据都是先进入Buffer的。Buffer的本质是一个数组,通常它是一个字节数组,也可以是其他类型的数组。Buffer是一个接口,它的实现类有ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。
-
Channel是一个通道,可以通过它读取和写入数据。与流不同的是,流是单向的,而Channel是双向的。数据可以通过Channel读到Buffer里,也可以通过Channel写入到Buffer里。为了支持不同的设备,Channel接口有好几种子类,如FileChannel用于访问磁盘文件、SocketChannel和ServerSocketChannel用于TCP协议的网络通信、DatagramChannel用于UDP协议的网络通信。
-
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)