目录
[1.leetcode 3.无重复字符的最长子串(中等)](#1.leetcode 3.无重复字符的最长子串(中等))
[2.leetcode 88. 合并两个有序数组(简单)](#2.leetcode 88. 合并两个有序数组(简单))
1.Kafka和RocketMQ的区别
虽然自己平时用RabbitMQ用得多一点,但是在选择RabbitMQ的时候也对这两个进行了一定的了解
1.适用的对象不同:RokcetMQ是阿里自己开发的,产品质量确实经过了阿里淘宝天猫的双11的检验,并发量也能达到十万级,Kafka适用于更大型的项目,支持的并发量更高,能达到几十万级,支持集群部署。
2.实现的引言和支持的语言不同:RocketMQ目前主要支持Java语言,C++都有所限制,其他的语言是不支持的,而Kafka支持的语言较多,但kafka有一个非常致命的缺点,就是可能会发生一小部分消息的丢失。
选择:如果能够允许一小部分的内容丢失,并且追求极高的吞吐量和高性能直接选Kafka,如果使用的是Java语言,并且也想用MQ的一些功能如:延迟队列,消息事务等就选RockctMQ
2.反射的作用
反射其实就是一个程序在运行的时候,对于一个类,无论这个类是什么类,不可继承类啊,父类子类啊,抽象类这些都能够获得其类的属性和方法,也不管这些属性和方法是由什么修饰符来修饰的,都能够获取。
反射有一些特性:
1.运行时类信息的访问。
2.动态对象的创建:通过反射API动态创建对象实例,即使在编译的时候不知道具体的类名,通过class类的newInstance和Constructor对象的newInstance方法实现的。
3.动态方法调用:通过Method类的invoke方法。
4.访问和修改字段值:通过Filed类的get和set方法实现。
优点就是可以动态地去获取对象实例,缺点是效率比较低(编译器无法优化,调用了很多其他方法),并且反射破坏了封装和类的私有方法,不安全。
3.类加载的具体过程,双亲委派模型的机制
类加载过程其实用大白话理解就是运行的时候,所写的类在JVM中是如何进行加载的
1.加载阶段:将字节码数据从不同的数据源读取到JVM中,并生成.class对象
2.连接:将原始的类信息转化为JVM运行的过程,这又分为3个部分
(1)验证:JVM得去验证所加载的类是安全的,不会出现一些非法的行为,要符合JVM虚拟机规范
(2)准备:创建类或接口的静态变量,并初始化静态变量的初始值,分配所需要的内存
(3)解析:将常量池的符号引用替换成直接引用(将符号表示的类,方法转换成内存地址等)
3.初始化阶段:真正去执行类初始化的代码逻辑,包括静态字段赋值等。
父亲委派模型:当要去加载一个类的时候,会交由其上一级加载器去判断有没有加载过,从下至上是自定义类加载器,应用程序类加载器,扩展类加载器,启动类加载器,目的是避免重复加载Java类型
4.TCP的四次挥手
进行数据传输的双方,因为某一方认为数据已经处理完毕,就向对方发起FIN报文,代表我这边已经不会再发送数据过去了,进入FIN_WAIT1状态,对方收到这个FIN报文之后,返回一个ACK,表示已经收到这个报文了,进入CLOSE_WAIT状态,接收到这个FIN报文之后,TCP协议栈会开启一个文件结束符EOF在接收缓冲区中,处理完缓冲区中的数据之后,也就是读到了EOF,这时对方就会发送一个FIN报文,代表对方也不会再发送数据了,进入LAST_ACK状态,此时我这边收到之后,返回一个确认ack,进入CLOSE状态,对方受到之后也进入CLOSE状态,到这里本次连接就结束了
5.多线程的优势
1.开启多个线程能帮我们处理某个任务的时候更快,例如处理400条数据,如果一个线程要1s中,那就需要400s,现在我有10个线程,同时去执行这样的操作,就只需要40s。
为什么不用进程是因为线程的创建和销毁的开销比进程小得多,linux中启动一个进程,操作系统要给他分配栈,堆,内存地址等。由于线程是共享内存数据,所以创建线程轻量很多。其次,进程之间的通信比较复杂,而线程很容易
6.死锁产生的原因,怎么解决
1.互斥条件:一个资源被一个线程占有之后,不能再被其他线程占有。
2.保持且请求:一个线程在占有一个资源的同时,去申请占有其他的资源
3.不可剥夺:一个线程不能强行从其他线程中剥夺部分资源
4.循环条件:A需要B的资源,B需要A的资源
解决方式只能从2,4入手,即资源有序分配法,A获取资源的顺序是1,2,3,4,那设置B获取资源的方式也是A,B,C,D
7.Java并发的工作原理
并发就是同一时间内执行多个线程,完成多个任务。Thread类和Runnable接口是实现并发的关键。线程的生命状态:新建,就绪,运行,阻塞,停止。
保证线程安全:1,原子性:通过加锁的方式保证同一时刻只有一个线程对资源进行修改,Java通过synchronized或者Atomic这样的关键字保证
2.可见性:通过synchronized和volatile这样的关键字保证,volatile的原理是读时,从主内存中读取数据,写时,先写工作内存之后刷新到主内存中
3.有序性:happens-before保证有序性
提供了很多锁机制:
1.内置锁:synchronized,JVM提供的。syncronized加锁时有无锁、偏向锁、轻量级锁和重量级锁几个级别。
2.ReentrantLock:JUC包下的一个锁,比synchronized高级一定,有一定的特殊用处(公平性,定时等)
3.读写锁
4.自旋锁:通过CAS进行实现
5.乐观锁和悲观锁:不先加锁(通过版本号或时间戳实现),直接加锁
8.常用的git命令
git pull从远程仓库拉代码 git add --将工作区代码的修改添加到暂存区 git commit -m将暂存区代码提交到本地仓库并添加相应的注释 git push 提交代码
想要撤回git commit 就使用git reset --soft HEAD 撤回add操作:git reset --mixed HEAD
撤回push:git push origin xxx --force 回退版本
9.算法题
1.leetcode 3.无重复字符的最长子串(中等)
java
public int lengthOfLongestSubstring(String s) {
int n = s.length();
int[] hash = new int[128];
int left=0,right=0;
// 用于返回结果
int ret = 0;
while(right<n){
char ch = s.charAt(right);
hash[ch]++;
while(hash[ch]>1){
char c = s.charAt(left);
hash[c]--;
left++;
}
ret = Math.max(ret,right-left+1);
right++;
}
return ret;
}
2.leetcode 88. 合并两个有序数组(简单)
java
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m-1;
int j = n-1;
int k = m+n-1;
while(i>=0 && j>=0){
// 大的放后面
if(nums1[i]>nums2[j]){
nums1[k--] = nums1[i--];
}else{
nums1[k--] = nums2[j--];
}
}
// 处理剩余的内容
while(j>=0){
nums1[k--] = nums2[j--];
}
}