零碎知识点
Java
- 下面这条语句的执行结果永远为0;
int count=0;
count=count++;
- 在JDK1.8之前,运行时常量池被放在方法区,属于线程共享,JDK1.8后,元空间取代了方法区,运行时常量池被放在元空间中,运行时常量池用来存放class文件元信息描述,编译后的代码,引用数据类型,类文件常量池。
- JAVA中char是两个字节,C++中是一个字节,且是有符号的。
- 类之间关系:USES-A依赖关系,关联关系、HAS-A聚合关系、IS_A继承关系
- Java中的ClassLoader:
- java中类的加载有5个过程,加载、验证、准备、解析、初始化;这便是类加载的5个过程。
- 类加载器的任务是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标类对应的java.lang.Class对象实例,在虚拟机提供了3种类加载器,引导(Bootstrap)类加载器、扩展(Extension)类加载器、系统(System)类加载器(也称应用类加载器);
- 一个类,由不同的类加载器实例加载的话,会在方法区产生两个不同的类,彼此不可见,并且在堆中生成不同Class实例;
- 加载器是肯定要保证线程安全的;
- 装载一个不存在的类的时候,因为采用的双亲加载模式,所以强制加载会直接报错java.lang.SecurityException: Prohibited package name: java.lang
- 双亲委派模式是在Java1.2后引入的,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成,所以默认是父装载;
- 自定义类加载器实现继承ClassLoader后重写了findClass方法加载指定路径上的class.
- Java socket
- ServerSocket(int port)创建一个serversocket绑定在特定的端口
- Socket(InetAddress address,int port)创建到特定的端口和ip地址
- 当线程在活动之前或活动期间处于正在等待、休眠或占用状态且该线程被中断时,抛出
InterruptedException
异常。
- 属于被动引用不会出发子类初始化
- 子类引用父类的静态字段,只会触发子类的加载、父类的初始化,不会导致子类初始化
- 通过数组定义来引用类,不会触发此类的初始化
- 常量在编译阶段会进行常量优化,将常量存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
- Java类初始化的时机详解
https://www.jianshu.com/p/3afa5d24bf71 - Java中线程Thread中的run方法使用start调用才是执行线程,否则就是普通的方法调用。
- Java文件与Bean所定义的类名可以不同,但一定要注意区分字母的大小写。
- interface中的方法默认为
public abstract
的,变量默认为public static
final的。 - 三元操作符类型的转换规则:
- 若两个操作数不可转换,则不做转换,返回值为Object类型
- 若两个操作数是明确类型的表达式(比如变量),则按照正常的二进制数字来转换,int类型转换为long类型,long类型转换为float类型等。
- 若两个操作数中有一个是数字S,另外一个是表达式,且其类型标示为T,那么,若数字S在T的范围内,则转换为T类型;若S超出了T类型的范围,则T转换为S类型。
- 若两个操作数都是直接量数字,则返回值类型为范围较大者。
- super和this
- super()表示调用父类构造函数、this()调用自己的构造函数,而自己的构造函数第一行要使用super()调用父类的构造函数,所以这俩不能在一个构造函数中会出现重复引用的情况
- super()和this()必须在构造函数第一行,所以这一点也表明他俩不能在一个构造函数中
- this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块(里面不能使用非static类型的)。
基础知识
- ANSI编码在简体中文操作系统中就是GB2312
- byte类型的变量参与运算时会转换成int进行,然后直接赋值给byte会报错。+=会自动强制类型转换;+必须手动强转。
- 二次探测再散列处理冲突方法:
如果发生冲突,则加上[12,-12,22,-22,32,-32],然后再求hash - 可以作为hadoop集群管理工具的有:puppet,Cloudera Manager,pdsh,zookeeper
- 多道程序设计:用户提交的作业先放在外存上,并排成一个队列,然后由作业调度程序按照一定的算法,从这个队列中选择若干作业调入内存,使他们共享CPU和内存中的资源,实现多道程序的交替进行。
- 数据库三级模式:外模式、模式、内模式。
- 外模式也称子模式,用户模式。对应于用户级。是数据库用户能够看见和使用的局部数据的逻辑结构和特征的描述,是数据库用户的数据视图,与某一应用有关的数据的逻辑表示。数据库操纵语言(DML)
- 模式也称逻辑模式,概念模式,概念级,是数据库中全体数据的逻辑结构和特征的描述,是所有用户的公共数据视图。数据模式描述语言(DDL)
- 内模式也称存储模式,对应物理级。是数据库中全体数据的内部表示或底层描述,是数据库最低一级的逻辑描述,描述了数据在存储介质上的存储方式和物理结构。
- 一个含抽象数据类型的软件模块模块应该包含定义、实现、表示
C++
- 对数组名取地址时,数组名不会被解释成其地址数组名会被解释成为其第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址。
操作系统
-
OS缺页置换算法:
当访问一个内存中不存在的页,并且内存已满,则需要从内存中调出一个页或将数据送至磁盘对换区,替换一个页,这种现象叫做缺页置换。当前操作系统最常采用的缺页置换算法如下:
FIFO、LRU -
进程和线程:
- 进程是CPU资源分配的最小单元,线程是CPU调度的最小单位。
- 进程有独立的系统资源,而同一进程内的线程共享大部分的系统资源。
- 一个进程崩溃,不会对其他进程产生影响;而一个线程崩溃,会让同一进程内的其他线程也死掉。
- 进程创建、切换、销毁时开销比较大,而线程比较小。
- 进程间通信复杂,线程间由于共享代码段和数据段,所以通信比较容易。
多进程适合CPU密集型,多机分布式场景。多线程主要优势是线程间切换代价小,适合I/O密集型的工作场景。
-
死锁和解决
死锁:两个或者两个以上进程再执行过程中,因争夺资源而造成的相互等待的现象。
四个条件:互斥、请求与保持、不可剥夺、环路等待
解决办法:
- 资源一次性分配 剥夺请求和保持条件、
- 可剥夺资源 破坏不可剥夺条件
- 资源有序分配法 破坏环路等待
-
虚拟内存和物理内存
与现代操作系统内存管理机制有关。进程使用虚拟内存,有操作系统负责虚拟内存空间到物理内存空间的地址映射。
-
段式管理
地址转换:
- 逻辑地址转线性地址【段标识符:段内偏移量】
线性地址 = 段开始地址 + 段内偏移量
扫描二维码关注公众号,回复: 11524773 查看本文章 -
页式管理
-
-
结构体对齐,字节对齐
- 原因:
- 不是所有的硬件平台都可以访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
- 数据结构应该尽可能地在自然边界上对齐。为了访问未对齐的内存,处理器需要做两次内存访问;而对齐的内存只需要一次访问内存。
- 规则:
- 数据成员对齐:
第一个数据成员放在offset为0的地方。以后每个数据按照#pragma back指定的数值和这个数据成员自身长度中比较小的那个进行。 - 整体对齐规则:
- 结构体作为成员:结构体成员要从其内部最大元素大小的整数倍地址开始存储。
-
进程间通信
管道、系统IPC(消息队列、信号量、信号、共享内存)、socket
- 管道: 半双工,一种存在于内存的特殊文件。用于父子进程或者兄弟进程之间的通信。
- 系统IPC
- 临界区:通过多线程的串行化来访问公共资源或一段代码
- 消息队列:内核中的消息链表。
- 信号量:用来控制多个进程对共享资源的访问。基于操作系统PV操作。
- 信号: 用于通知接收进程某个事件已经发生。
- 共享内存:多个进程访问同一块内存,不同进程可以及时看到对方进程中对共享内存数据的修改。
- socket可以用于不同主机之间的进程通信
- 互斥锁和读写锁:
- 互斥锁:用来保证在任何时刻都只能有一个线程访问该对象。不区分读写。
- 读写锁:处于读操作时,可以允许多个线程同时获得读操作。但同一时刻只能有一个线程获得写锁,此时不能有其他任何线程获得读锁。
-
进程状态转换图
-
创建、就绪、执行、阻塞、终止
- 执行-》就绪: 时间片到,高优先级
- 执行-》阻塞: 等待某事件,IO中断,等待设备
- 就绪-》执行:调度
- 阻塞-》就绪:事件发生
-
交换技术
多个进程竞争资源时,会造成内存资源紧张。I/O速度与CPU速度严重不匹配1)交换技术: 换出一部分进程到外村
2)虚拟存储技术:每个进程只能装入一部分程序和数据。 -
活动阻塞、静止阻塞、活动就绪、静止就绪
活动阻塞/就绪:进程再内存
静止阻塞/就绪:进程再外存
活动就绪-》静止就绪:内存不够
活动阻塞-》静止阻塞:内存不够
执行-》静止就绪 时间片用完 -
-
大端和小端
大端指低字节存储在高地址;小端指低字节存储在低地址。
- 用户态和内核态
用户态(目态)和内核态(管态)是操作系统的两种不同到运行级别。两者区别是特权级不同。用户态拥有最低的特权级,内核态拥有较高的特权级。用户态的程序不能直接访问操作系统内核数据结构和程序。内核态和用户态的转换方式主要包括:系统调用、异常、中断。
-
小问题
- 怎么确定线程是繁忙还是阻塞?使用ps命令查看
- 怎么唤醒被阻塞的socket线程?给阻塞线程缺少的资源
- 如何设计server使其接受多个客户端请求? 多线程、线程池、IO复用
- 就绪的进程再等待什么? 被调度使用CPU的权利
-
内存溢出和内存泄漏
- 内存溢出:程序申请内存时,没有足够的内存供申请者使用。
- 内存泄漏: 由于疏忽或错误造成了程序未能释放掉不再使用的内存的情况。
- 堆内存泄漏: new/delete malloc/free没有配对使用
- 系统资源泄漏
- 没有将基类的析构函数定义为虚函数。
-
常用线程模型
- Future模型:结合Callable接口配合使用。把结果放在将来获取,当前主线程并不急于获取处理结果。允许子线程先进行处理一段时间,处理结束就把结果保存下来,当主线程需要使用的时候再向子线程索取。
- fork/join模型 递归和回溯思想
- actor模型 基于消息传递机制并行任务处理思想
- 生产者消费者模型
- master-worker模型
- 协程
微线程,看似子程序,但是执行过程可中断
- 协程和线程:极高的执行效率 不需要线程切换,不需要同步
- 多进程+协程
-
系统调用
运行在用户态的程序向操作系统内核请求需要更高运行权限运行的服务。用户与操作系统之间的接口。借由中断来实现。 -
源码到可执行文件
- 预编译
- 编译
- 汇编 (到汇编)
- 链接 到机器码(目标程序)
- 5种IO模型
- 阻塞
- 非阻塞:调用了之后,可以做其他事,每隔一段时间轮询IO事件是否就绪。
- 信号驱动:当IO就绪,进程会收到sigio信号
- IO复用:同时阻塞多个IO操作,并对多个读操作、写操作的IO函数进行检测
- 异步IO:告诉内核描述字缓冲区指针和大小文件偏移通知方式,然后立即返回。当内核将数据拷贝到缓冲区后,再通知应用程序。
-
如何实现线程池
- 设置一个生产者消费者队列,作为临界资源
- 初始化N个进程,并让其运行起来,加锁去队列取任务运行
- 任务队列为空时,所有线程阻塞
计算机网络
-
TCP如何保证可靠性
- 序列号、确认应答、超时重传
- 窗口控制与高速重发控制、快速重传
- 拥塞控制 慢启动、拥塞避免
-
TCP模型
应用层、传输层、网络层、链路层 TCP/IP -
http和https区别
-
http是明文传输;https是经过tls或者ssl加密的。
-
http在tcp之后还要ssl的handshake,使用非对称加密协商数据传输阶段的对称秘钥
-
https需要服务器申请证书
-
https端口443 http 80
-
https缺点:握手阶段延迟较高,部署成本高;加解密占用服务器CPU资源
-
-
网络地址
- MAC地址:负责数据链路层传输;
- IP地址:网络层传输;屏蔽物理地址的差异
-
GET和POST
- GET:浏览器会把http header和data一并发送出去,服务器响应200
通过url传参,url传参有长度限制,只能通过url编码,服务器会主动cache;而post没有,支持多种编码方式。get请求的参数产生一个TCP数据包 - POST:浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok
产生两个TCP数据包
- GET:浏览器会把http header和data一并发送出去,服务器响应200
-
TCP/IP数据链路层的交互过程
网络层等到数据链路层用mac地址作为通信目标,数据包到达网络等准备网数据链路层的时候,首先会去自己的ARP映射表查找该目标ip的mac地址,如果找到,就将目标ip的mac地址封装到链路层数据包的包头。如果没有,会发起一个广播:who is ip xxx tell ip xxx所有收到广播的机器看这个ip是不是自己,如果是,单拨将自己的mac地址回复给请求的机器。
数据库
-
数据库事务的4个特性
一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元。
-
原子性:不可再分,所有操作要么全部失败,要么全部成功
-
一致性:事务必须是数据库从一个一致性状态变换到另外一个一致性状态。
-
隔离性:多个用户并发访问数据库,数据库为每个用户开启的事务不被其他事务干扰。
不同的隔离级别:
- 读取未提交:一个事务可以读到另一个事务未提交的结果
- 读取提交内容:只有事务提交后,其更新结果才被其他事务可见。
- 可重复度:在一个事务中,对于同一份数据的读取结果总是相同。
- 可串行化:牺牲了并发性。
-
持久性:事务一旦提交,对数据库的改变就是永久的。
-
-
数据库三大范式
- 第一范式:属性不可分解
- 第二范式:非主属性都完全依赖于R的每一个候选关键词
- 第三范式:非主属性不传递依赖于键码
-
mysql的MVCC机制
多版本并发控制机制,innoDB存储引擎实现隔离级别的一种具体实现,用于实现提交读和可重复读。通过某个时间点的快照来实现。每行记录后面保存两个隐藏的列,分别保存行的创建版本号和删除版本号。快照存储在undo日志中,日志通过回滚指针将数据行所有快照链接。
-
MySQL引擎
数据库引擎是用于存储、处理和保护桑树的核心服务。利用数据库引擎可控制访问权限并快速处理事务,从而满足企业内大多数需要处理大量数据的应用程序的要求。常见引擎:InnoDB和MyIsam、Memor、Archive-
InnoDB事务型存储引擎,有行级锁和外键约束。提供了对ACID的支持,和4中隔离级别的支持。
适用场景:经常更新、多重并发,通过bin-log日志灾难恢复,外键约束、自动增加、索引 索引即数据 -
MyIsam是MySQL默认引擎,但是没有对事务的支持,不支持行级锁和外键。insert和update会锁定整个表。
-
优点:极度强调快速读取性能。适用于读大于写,且不需要事务。
-
缺点:不能在表损坏后主动恢复数据。
-
二者区别:
项目 MyISAM InnoDB 事务 不支持 支持 性能 高 低 行数保存 保存 不保存 索引存储 支持全文索引 不支持全文索引 索引与数据 分开存储 整合 备份 文件存储,备份简单 拷贝数据备份,数据量大备份麻烦 锁 只支持表锁 支持行锁
-
-
Redis
- redis 和 Mongodb
项目 redis mongodb 内存管理 数据全部存储在内存,定期写入磁盘,可选LRU删除数据 数据存在内存,内存不够时,只将热点数据放入内存,其他存在磁盘。 数据结构 hash set list等 结构单一 -
redis定时机制:
redis服务器是一个事件驱动程序,服务器处理两类时间:文件事件、时间事件。 redis定时机制通过时间事件来实现。时间事件三要素:id时间事件标识号、when时间事件到达时间、timeproc时间事件处理器 -
redis单线程为什么高效? I/O复用
-
redis的渐进rehash
如果k很多,一次性对所有键值进行rehash,庞大的计算量很容易导致服务器挂掉。所以redis分多次渐进式的rehash:- 操作redis时,额外做一步rehash
- 后台定时任务调用rehash
-
redis和memcached
项目 redis mongodb 数据类型 丰富 单一 持久性 支持 不支持 分布式存储 master-slave复制 一致性hash value大小 不限制 key长度小于250字符,单个item小于1m 数据一致性 单线程,保证按序提交 cas 乐观锁 CPU利用 单线程只能利用一个cpu,可以开启多个进程
算法和数据结构
-
树
-
平衡二叉树(AVL树)
特殊二叉排序树 -
红黑树
一种二叉查找树,每个节点存储红色或黑色,一种弱平衡二叉树,插入最多旋转二次,删除最多旋转三次
-
-
哈夫曼编码
利用字符在文件中出现的频率来建立0 1 表示字符的最优方式。自底向上构造表示最优前缀的二叉树。 -
栈与堆:
栈是操作系统提供的数据结构;堆是C++库函数提供的,机制复杂。 -
长度为N的整形数组,每个元素取值[0,n-1],判断该数组是否有重复的数字
思路:把每个数放到自己对应序号的位置上去,如果其他位置有和自己对应的数,则重复。
bool isDuplicateNumber(int *array,int n){
if(array==NULL) return false;
int temp;
for(int i=0;i<n;i++){
while(array[i]!=i){
if(array[array[i]]==array[i])
return true;
temp=array[array[i]];
array[array[i]]=array[i];
array[i]=temp;
}
}
return false;
}
-
TOP(K)问题
- 直接全部排序
- 快排变形
- 最小堆法
- 分治法
数据分成N分,找到每份中最大的K个数。剩下N*K个数。然后再分治。直到剩余数可以读入内存。 - hash
如果数据重复率很高,则先通过hash法去重。
-
hash表的实现
构造哈希和处理哈希冲突。- 构造方法
- 直接地址法
- 平方取中法
- 除留余数法
- 处理冲突
- 开放定址法
- 线性探查
1 2 3 … m-1 - 二次探查
12 -12 22 -22 32 -32 - 伪随机数序列
- 线性探查
- 再哈希法
- 链地址法
- 建立公共溢出区
- 开放定址法
- rehash hash表中的负载因子loadFactor小于1时,可以继续添加。等于1时就需要rehash了。桶数组变为原来两倍,然后将所有元素重新哈希到新桶。
- 哈希桶个数为什么是质数? 最大程度减少冲突概率
- 构造方法
-
加密方法
-
单向加密
- MD5加密:非可逆,单向散列。相同明文可产生相同的密文
- SHA 对任意长度数据生成160位的数值。
- CRC-32 主要用于校验
-
对称加密
使用单个秘钥系统的加密方法- 优点 速度快,算法公开,计算量小
- 缺点 秘钥泄漏加密信息就不安全了。秘钥管理负担大
-
非对称加密
公钥加密 公钥是私钥提取出来的。公钥加密,私钥解密。私钥加密,公钥解密。常用于加密和数字签名。发送方用对方的公钥加密,保证数据的机密性
发送方用自己的私钥加密 实现身份验证。
速度慢,通常用来身份验证。
-
设计模式
-
OOP的五项原则
- 单一职责原则
- 接口隔离原则 接口不宜过大,多个专门接口比单个接口好
- 开放-封闭原则
对扩展开放,对修改封闭。 - 替换原则 子类必须能够替换掉他们的父类型,并出现在负类能够出现的任何地方。
- 依赖倒置原则
上层模块不应该依赖于下层模块。父类不能依赖于子类,都要依赖于抽象类。
抽象不能依赖于具体,具体应该依赖于抽象。
-
单例模式:解决全局使用的类频繁创建和销毁的问题。单例模式确保某一个类只有一个实例。
- 饿汉式:上来就实例化,避免多线程同步问题。可能会产生垃圾对象。
- 懒汉式:通过双重锁机制实现线程安全
// java实现
public class Singleton{
private static Singleton instance;
Singleton(){
}
public static Singleton getInstance(){
if(instance==NULL){
synchronized(Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
- 如何保证单利模式只有唯一实例
- 构造函数私有
- 类内提供静态方法
饿汉式线程安全;懒汉式需要实现线程安全。
-
工厂模式:解决接口选择问题。定义一个创建对象的接口,让其子类自行决定实例化那个工厂类
-
观察者模式:一对多的一类。当一个对象的状态发生改变时,所有依赖于它的对象都可到通知并自动更新。
-
装饰器模式:对已经存在的某些类进行装饰,来扩展功能。通过对象的关联关系代替继承