- java基础
-
HashMap的底层实现
-
HashMap的底层实现主要是基于数组和链表来实现的,HashMap中通过key的hashCode来计算hash值的,由这个hash值计算在数组中的位置,将新插入的元素放到数组的这个位置,如果新插入的元素的hash值跟这个位置上已有元素的hash值相同,就会出现hash冲突,这时候,就在该位置通过链表来插入新的元素。
-
在Jdk1.8中HashMap的实现方式做了一些改变,但是基本思想还是没有变得,只是在一些地方做了优化,下面来看一下这些改变的地方,数据结构的存储由数组+链表的方式,变化为数组+链表+红黑树的存储方式,当链表长度超过阈值(8)时,将链表转换为红黑树。在性能上进一步得到提升。
算法 - Algorithm
-
排序算法:快速排序、归并排序、计数排序
搜索算法:回溯、递归、剪技技巧
图论:最短路、最小生成树、网络流建模
动态规划:背包问题、最长子序列、计数问题
基础技巧:分治、倍增、二分、贪心
数据结构
-
数组与链表:单/双向链条表、跳舞链
栈与队列
树与图
哈希表
堆:大/小根堆、可并堆
字符串:字典树、后缀树
- 数据库
-
优化:
-
mysql:多用联表查询,不使用子查询,用in来替换or
-
oracle:SGA:SystemGlobal Area是OracleInstance的基本组成部分,在实例启动时分配;系统全局域SGA主要由三部分构成:共享池、数据缓冲区、日志缓冲区。
对于SQL调优,可以通过Oracle的执行计划来分析。 -
使用先使用范围查询定位 id (或者索引),然后再使用索引进行定位数 据,能够提高好几倍查询速度。即先 select id,然后再 select *;
存储过程
- linux
Linux查看日志常用命令
1.查看日志常用命令
tail:
-n 是显示行号;相当于nl命令;例子如下:
tail -100f test.log 实时监控100行日志
tail -n 10 test.log 查询日志尾部最后10行的日志;
tail -n +10 test.log 查询10行之后的所有日志;
head:
跟tail是相反的,tail是看后多少行日志;例子如下:
head -n 10 test.log 查询日志文件中的头10行日志;
head -n -10 test.log 查询日志文件除了最后10行的其他所有日志;
cat:
tac是倒序查看,是cat单词反写;例子如下:
cat -n test.log |grep "debug" 查询关键字的日志
2. 应用场景一:按行号查看---过滤出关键字附近的日志
1)cat -n test.log |grep "debug" 得到关键日志的行号
2)cat -n test.log |tail -n +92|head -n 20 选择关键字所在的中间一行. 然后查看这个关键字前10行和后10行的日志:
tail -n +92表示查询92行之后的日志
head -n 20 则表示在前面的查询结果里再查前20条记录
3. 应用场景二:根据日期查询日志
sed -n '/2014-12-17 16:17:20/,/2014-12-17 16:17:36/p' test.log
特别说明:上面的两个日期必须是日志中打印出来的日志,否则无效;
先 grep '2014-12-17 16:17:20' test.log 来确定日志中是否有该 时间点
4.应用场景三:日志内容特别多,打印在屏幕上不方便查看
(1)使用more和less命令,
如: cat -n test.log |grep "debug" |more 这样就分页打印了,通过点击空格键翻页
(2)使用 >xxx.txt 将其保存到文件中,到时可以拉下这个文件分析
如:cat -n test.log |grep "debug" >debug.txt
-
微服务模块
集群和分布式:
通俗讲法
集群:多个人在一起作同样的事 。
分布式 :多个人在一起作不同的事 。ACP理论:
1:一致性:读操作总是能读取到之前完成的写操作结果,满足这个条件的系统称为强一致系统,这里的“之前”一般对同一个客户端而言,
2:可用性:读写操作在单台机器发生故障的情况下仍然能够正常执行,而不需要等待发生故障的机器重启或者其上的服务迁移到其他机器,
3:分区可容忍性:机器故障、网络故障、机房停电等异常情况下仍然能够满足一致性和可用性。 -
Eureka 的通俗理解:
1: 3y跟女朋友去东站的东方宝泰逛街,但不知道东方宝泰有什么好玩的。于是就去物业搜了一下东方宝泰商户清单,发现一楼有优衣库,二楼有星巴克,三楼有麦当劳。
2:在优衣库旁边,有新开张的KFC,在墙壁打上了很大的标识“欢迎KFC入驻东方宝泰”。
3:商家们需要定时交物业费给物业。
4:物业维持东方宝泰的稳定性。如果某个商家不想在东方宝泰运营了,告诉了物业。物业自然就会将其在东方宝泰商户清单去除。
Ribbon:客户端的负载均衡
Niginx:服务端的负载均衡
Hystrix的通俗理解:
1:3y和女朋友决定去万达玩,去到万达的停车场发现在负一层已经大大写上“负一层已停满,请下负二层,负二层空余停车位还有100个!”
2:这时,3y就跟女朋友说:“万达停车场是做得挺好的,如果它没有直接告知我负一层已满,可能我就去负一层找位置了,要是一堆人跑去负一层但都找不到车位的话,恐怕就塞死了”。3y接着说:“看停车位的状态也做得不错,在停车位上头有一个感应(监控),如果是红色就代表已被停了,如果是绿色就说明停车位是空的”
Feign整合了Riddon和Hystrix。
可以像调用本地方法一样调用远程服务
Zuul 与Eureka 进行整合,将自身注册到Eureka服务治理下的应用,同时从Eureka中获取了所有其他微服务的实例信息。
mq怎么用,为什么用,不用行不行
1、什么是RabbitMQ?为什么使用RabbitMQ?
答:RabbitMQ是一款开源的,Erlang编写的,基于AMQP协议的,消息中间件;
可以用它来:解耦、异步、削峰。
2、RabbitMQ有什么优缺点?
答:优点:解耦、异步、削峰;
缺点:降低了系统的稳定性:本来系统运行好好的,现在你非要加入个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性会降低;
增加了系统的复杂性:加入了消息队列,要多考虑很多方面的问题,比如:一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等。因此,需要考虑的东西更多,复杂性增大。
- Redis
1:当第一次读取数据的时候,读取 Redis 的数据就会失败,此时就会触发程序读取数据库,把数据读取出来,并且写入 Redis 中;
2:当第二次以及以后需要读取数据时,就会直接读取 Redis,读到数据后就结束了流程,这样速度就大大提高了。
nginx
- git使用问题
基础命令:
cd 进入相对于当前路径的下一级目录
ls 当前文件夹下的情况
ll 当前文件的情况详情
Ctrl+l 清屏
cd … 回到上级目录
touch 创建文件
git diff 查看修改哪里了
git diff HEAD – a.txt 对比工作区和版本库中的不同
git log 查提交历史记录,以便回退到哪个版本
git reflog查看命令历史,以便确定要回到未来的哪个版本
git reset --hard HEAD^ 回退到上一个版本
git reset HEAD 可以把暂存区的修改撤销掉,重新回到工作区
git checkout – file 当你改乱了工作区某个文件的内容,可直接丢弃工作区的修改,变成和版本库一样的
git push -u origin master 第一次推送本地库到远程库
git push origin master 后续推送本地库到远程库
进入vim 如何退出
如果是输出状态,首先按Esc键退出输入状态,然后按Shift+“;”,再输入q!或wq!(q!不保存改动,wq!是保存文件的写入修改)退出。
删除当前的版本库 $ rm -rf .git
创建版本库 $ git init
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
git checkout master 切换到
bug 分支:
先将当前工作现场隐藏。git stash
创建新的临时分支 git checkout -b issue-404
合并分支 :git merge --no-ff -m ‘merge bug fix404’ issue-404
删除分支:git branch -d issue-404
rebase操作的特点:把分叉的提交历史“整理”成一条直线,看上去更直观。缺点是本地的分叉提交已经被修改过了
Git鼓励大量使用分支:
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
- spring
spring核心有两部分:
(1)控制反转 ioc:
-
比如现在有普通类,在这个类里面有普通的方法,调用这个类里面的普通的方法,需要创建类对象,使用对象调用方法。
-
创建类的对象,使用原始方式new对象。使用ioc实现对象创建,不需要手动new对象,通过配置文件方式创建对象 把对象创建交给spring配置
-
工厂模式;
(2)面向切面 aop:
-
不通过修改源代码方式增强类里面的方法
-
aop底层动态代理
String/StrngBuffer/Stringbuilder
1、在字符串不经常发生变化的业务场景优先使用String(代码更清晰简洁)。如常量的声明,少量的字符串操作(拼接,删除等)。
2、在单线程情况下,如有大量的字符串操作情况,应该使用StringBuilder来操作字符串。不能使用String"+"来拼接而是使用,避免产生大量无用的中间对象,耗费空间且执行效率低下(新建对象、回收对象花费大量时间)。如JSON的封装等。
3、在多线程情况下,如有大量的字符串操作情况,应该使用StringBuffer。如HTTP参数解析和封装等。
-
多线程
所以实现线程的几种方式就有了,1、继承Thread目的重写run方法;2、实现Runnable接口,实现run方法;3实现Callable接口,回调获取线程结果。1。单进程单线程:一个人在一个桌子上吃菜。
2。单进程多线程:多个人在同一个桌子上一起吃菜。
3。多进程单线程:多个人每个人在自己的桌子上吃菜。 -
知识点10:银行家算法
一个银行家共有20亿财产,3个开发商客户。第一个开发商:已贷款15亿,资金紧张还需3亿;第二个开发商:已贷款5亿,运转良好能收回;第三个开发商:欲贷款18亿。
在这种情况下,如果你是银行家会怎么处理?一个常规的想法就是先等着第二个开发商把钱收回来,然后手里有了5个亿,再把3个亿贷款给第一个开发商,等第一个开发商收回来18个亿,然后再把钱贷款给第三个开发商。
这个故事的意义就是眼光放长一点,不要只看着手里有多少钱,同时要注意到别人欠自己的钱怎么能收回来。同理,在操作系统中,有内存,硬盘等等资源被众多进程渴求着,也可以通过类似的合理安排先后顺序来防止死锁。
首先定义安全序列:对当前申请资源的进程排出一个序列,保证按照这个序列分配资源能完成所有进程。假设有进程P1,P2,…Pn,则安全序列要求满足:Pi(1<=i<=n)需要资源<=剩余资源 + 分配给Pj(1 <= j < i)资源。
存在安全序列则不会发生死锁,不存在安全序列则可能发生死锁。安全序列未必唯一。
其次定义需要的数据结构: int n,m; //系统中进程总数n和资源种类总数m int Available[1..m]; //每种资源当前可用总量 int Allocation[1..n,1..m]; //当前给分配给每个进程的各种资源数量 int Need[1..n,1..m];//当前每个进程还需分配的各种资源数量 int Work[1..m]; //当前可分配的资源 bool Finish[1..n]; //进程是否结束 判定安全序列的算法为: 1. 初始化 Work = Available(动态记录当前剩余资源) Finish[i] = false(设定所有进程均未完成) 2. 查找可执行进程Pi(未完成但目前剩余资源可满足其需要,这样的进程是能够完成的) Finish[i] = false Need[i] <= Work 如果没有这样的进程Pi,则跳转到第4步 3. 若有则Pi一定能完成,且完成后会归还其占用的资源,即: Finish[i] = true Work = Work +Allocation[i] GOTO 第2步,继续查找 4. 如果所有进程Pi都是能完成的,即Finish[i]=ture,则系统处于安全状态,否则系统处于不安全状态。
-
线程池相关
-
线程池可以看做是线程的集合。在没有任务时线程处于空闲状态,当请求到来:线程池给这个请求分配一个空闲的线程,任务完成后回到线程池中等待下次任务**(而不是销毁)。这样就实现了线程的重用。
-
线程池内的线程数的大小相关的概念有两个,一个是核心池大小,还有最大池大小。如果当前的线程个数比核心池个数小,当任务到来,会优先创建一个新的线程并执行任务。当已经到达核心池大小,则把任务放入队列,为了资源不被耗尽,队列的最大容量可能也是有上限的,如果达到队列上限则考虑继续创建新线程执行任务,如果此刻线程的个数已经到达最大池上限,则考虑把任务丢弃。
排序:
/**
* 冒泡排序算法
*/
public static void bubbleSort(int[] list) {
int len = list.length ;
// 做多少轮排序(最多length-1轮)
for (int i = 0; i < len - 1; i++) {
// 每一轮比较多少个
for (int j = 0; j < len - 1 - i; j++) {
if (list[j] > list[j + 1]) {
// 交换次序
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
设计模式之单例模式
枚举类方式:
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){
return INSTANCE;
}
}
通信方面:
什么时候用长连接,短连接?
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。
而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。
- mvc
model 包含包装数据类和处理类(所说的数据bean和server层)