前言
只有光头才能变强
本文力求简单讲清每个知识点,希望大家看完能有所收获
一、如何减少线程上下文切换
使用多线程时,不是多线程能提升程序的执行速度,使用多线程是为了更好地利用CPU资源!
程序在执行时,多线程是CPU通过给每个线程分配CPU时间片来实现的,时间片是CPU分配给每个线程执行的时间,因时间片非常短,所以CPU通过不停地切换线程执行。
线程不是越多就越好的,因为线程上下文切换是有性能损耗的,在使用多线程的同时需要考虑如何减少上下文切换
一般来说有以下几条经验
还可以考虑我们的应用是IO密集型的还是CPU密集型的。
- 如果是IO密集型的话,线程可以多一些。
- 如果是CPU密集型的话,线程不宜太多。
参考资料:
二、计算机网络
2.1MAC地址已经是唯一了,为什么需要IP地址?
或者可以反过来问:已经有IP地址了,为什么需要MAC地址??在zhihu上还蛮多类似的问题的:

我来简单总结一下为什么有了MAC(IP)还需要IP(MAC):
- MAC是链路层,IP是网络层,每一层干每一层的事儿,之所以在网络上分链路层、网络层(...,就是将问题简单化。
- 历史的兼容问题。
已经有IP地址了,为什么需要MAC地址??
MAC地址已经是唯一了,为什么需要IP地址?
如果有更好的看法,不妨在评论区下留言哦~
参考资料:
2.2TCP状态
TCP 每个状态说一下,TIME-WAIT状态说一下
TCP总共有11个状态,状态之间的转换是这样的:

流程图:

下面我简单总结一下每个状态:
TIME_WAIT状态一般用来处理以下两个问题:

- 关闭TCP连接时,确保最后一个ACK正常运输(或者可以认为是:等待以便重传ACK)
- 网络上可能会有残余的数据包,为了能够正常处理这些残余的数据包。使用TIME-WAIT状态可以确保在创建新连接时,先前网络中残余的数据都丢失了。
TIME_WAIT过多怎么解决?
如果在高并发,多短链接情景下,TIME_WAIT就会过多。
可以通过调整内核参数解决:vi /etc/sysctl.conf
加入以下内容设置:
- reuse是表示是否允许重新应用处于TIME-WAIT状态的socket用于新的TCP连接;
- recyse是加速TIME-WAIT sockets回收
我们可以知道TIME_WAIT状态是主动关闭连接的一方出现的,我们不要轻易去使用上边两个参数。先看看是不是可以重用TCP连接来尽量避免这个问题(比如我们HTTP的KeepAlive)~
参考资料:
2.3TCP滑动窗口
TCP是一个可靠的传输协议,它要保证所有的数据包都可以到达,这需要重传机制来支撑。
重传机制有以下几种:
滑动窗口可以说是TCP非常重要的一个知识点。TCP的滑动窗口主要有两个作用:
简略滑动窗口示意图:

详细滑动窗口示意图:

1已收到ack确认的数据。
2发还没收到ack的。
3在窗口中还没有发出的(接收方还有空间)。
4窗口以外的数据(接收方没空间)
接受端控制发送端的图示:

2.4拥塞控制
TCP不是一个自私的协议,当拥塞发生的时候,要做自我牺牲。就像交通阻塞一样,每个车都应该把路让出来,而不要再去抢路了
拥塞控制主要是四个算法:
- 1)慢启动,
- 2)拥塞避免,
- 3)拥塞发生,
- 4)快速恢复
拥塞控制的作用:

拥塞的判断:

强烈建议阅读:
参考资料:
三、操作系统
3.1僵尸进程和孤儿进程是什么(区别)
unix/linux环境下

僵尸进程:
- 父进程创建出子进程,子进程退出了,父进程没有调用
wait
或waitId
获取子进程的信息(状态),子进程的描述符仍在系统中。
孤儿进程:
- 父进程退出,子进程仍在运行中。这些子进程就叫做孤儿进程,孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作
僵尸进程危害:
- 系统进程表是一项有限资源,如果系统进程表被僵尸进程耗尽的话,系统就可能无法创建新的进程。
- 一个父进程创建了很多子进程,就是不回收,会造成内存资源的浪费。
解决僵尸进程的手段:
- 杀掉父进程,余下的僵尸进程会成为孤儿进程,最后被init进程管理
- 子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程
- fork两次:原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程
参考资料:
3.2操作系统进程间通信的方式有哪些?
首先要知道的是:进程和线程的关注点是不一样的:
-
进程间资源是独立的,关注的是通讯问题。
-
线程间资源是共享的,关注的是安全问题。
操作系统进程间通信的方式有哪些?
3.3操作系统线程间通信的方式有哪些?
操作系统线程间通信的方式有哪些?(可以直接理解成:线程之间同步的方式有哪些)
- 锁机制:包括互斥锁、条件变量、读写锁
- 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
- 信号机制(Signal):类似进程间的信号处理
线程间的通信目的主要是用于线程同步。
参考资料:
扩展阅读:
3.4操作系统进程调度算法有哪些?
操作系统进程调度算法有哪些?
-
先来先服务算法(FCFS)
-
短进程/作业优先算法(SJF)
-
最高响应比优先算法(HRN)
-
最高优先数算法
-
基于时间片的轮转调度算法
-
最短剩余时间优先算法
-
多级反馈排队算法
- 设置多个就绪队列,分别赋予不同的优先级,如逐级降低,队列1的优先级最高
参考笔记:
四、拓展阅读
此部分是看别人的博文已经写得很好了,分享给大家~
4.1ConcurrentHashMap中的扩容是否需要对整个表上锁?
ConcurrentHashMap中的扩容是否需要对整个表上锁?
总结(摘抄)要点:
- 通过给每个线程分配桶区间(默认一个线程分配的桶是16个),避免线程间的争用。
- 通过为每个桶节点加锁,避免 putVal 方法导致数据不一致。
- 同时,在扩容的时候,也会将链表拆成两份,这点和 HashMap 的 resize 方法类似。
参考资料:
4.2什么是一致性Hash算法(原理)?
什么是一致性Hash算法(原理)?
总结(摘抄)要点:
参考资料:
4.3MySQL date、datetime和timestamp类型的区别
MySQL date、datetime和timestamp类型的区别
总结(摘抄)要点:
- date精确到天,datetime和timestamp精确到秒
-
datetime和timestamp的区别:
- timestamp会跟随设置的时区变化而变化,而datetime保存的是绝对值不会变化
- timestamp储存占用4个字节,datetime储存占用8个字节
- 可表示的时间范围不同,timestamp只能到表示到2038年,datetime可到9999年
参考资料:
4.4判断一个链表是否有环/相交
判断一个链表是否有环(实际上就是看看有无遍历到重复的节点),解决方式(3种):
- for遍历两次
- 使用hashSet做缓存,记录已遍历过的节点
- 使用两个指针,一前一后遍历,总会出现
前指针==后指针
的情况
参考资料:
判断两个无环链表是否相交,解决方式(2种):
判断两个有环链表是否相交(注:当一个链表中有环,一个链表中没有环时,两个链表必不相交):
- 找到第一个链表的环点,然后将环断开(当然不要忘记了保存它的下一个节点),然后再来遍历第二个链表,如果发现第二个链表从有环变成了无环,那么他们就是相交的嘛,否则就是不相交的了。
参考资料:
4.5keepAlive含义
- HTTP协议的Keep-Alive意图在于连接复用,同一个连接上串行方式传递请求-响应数据
- TCP的KeepAlive机制意图在于保活、心跳,检测连接错误
参考资料:
最后
如果大家有更好的理解方式或者文章有错误的地方还请大家不吝在评论区留言,大家互相学习交流~~~
如果想看更多的原创技术文章,欢迎大家关注我的微信公众号:Java3y。Java技术群讨论:742919422。公众号还有海量的视频资源哦,关注即可免费领取。
可能感兴趣的链接: