【Java】留下没有基础眼泪的面试题

前言

只有光头才能变强

本文力求简单讲清每一个知识点,但愿你们看完能有所收获html

1、如何减小线程上下文切换

使用多线程时,不是多线程能提高程序的执行速度,使用多线程是为了更好地利用CPU资源linux

程序在执行时,多线程是CPU经过给每一个线程分配CPU时间片来实现的,时间片是CPU分配给每一个线程执行的时间,因时间片很是短,因此CPU经过不停地切换线程执行面试

线程不是越多就越好的,由于线程上下文切换是有性能损耗的,在使用多线程的同时须要考虑如何减小上下文切换算法

通常来讲有如下几条经验shell

  • 无锁并发编程。多线程竞争时,会引发上下文切换,因此多线程处理数据时,能够用一些办法来避免使用锁,如将数据的ID按照Hash取模分段,不一样的线程处理不一样段的数据
  • CAS算法。Java的Atomic包使用CAS算法来更新数据,而不须要加锁
  • 控制线程数量。避免建立不须要的线程,好比任务不多,可是建立了不少线程来处理,这样会形成大量线程都处于等待状态
  • 协程。在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换编程

    • 协程能够当作是用户态自管理的“线程”不会参与CPU时间调度,没有均衡分配到时间。非抢占式

还能够考虑咱们的应用是IO密集型的仍是CPU密集型的。缓存

  • 若是是IO密集型的话,线程能够多一些。
  • 若是是CPU密集型的话,线程不宜太多。

参考资料:安全

2、计算机网络

2.1MAC地址已是惟一了,为何须要IP地址?

或者能够反过来问:已经有IP地址了,为何须要MAC地址??在zhihu上还蛮多相似的问题的:服务器

我来简单总结一下为何有了MAC(IP)还须要IP(MAC):微信

  • MAC是链路层,IP是网络层,每一层干每一层的事儿,之因此在网络上分链路层、网络层(...,就是将问题简单化。
  • 历史的兼容问题。

已经有IP地址了,为何须要MAC地址??

  • 现阶段理由:DHCP基于MAC地址分配IP

MAC地址已是惟一了,为何须要IP地址?

  • MAC无网段概念,非类聚,很差管理
若是有更好的见解,不妨在评论区下留言哦~

参考资料:

2.2TCP状态

TCP 每一个状态说一下,TIME-WAIT状态说一下

TCP总共有11个状态,状态之间的转换是这样的:

流程图:

下面我简单总结一下每一个状态:

  • CLOSED:初始状态,表示TCP链接是“关闭着的”或“未打开的”。
  • LISTEN:表示服务器端的某个SOCKET处于监听状态,能够接受客户端的链接。
  • SYN-SENT:表示客户端已发送SYN报文。当客户端SOCKET执行connect()进行链接时,它首先发送SYN报文,而后随即进入到SYN_SENT状态。
  • SYN_RCVD:表示服务器接收到了来自客户端请求链接的SYN报文。当TCP链接处于此状态时,再收到客户端的ACK报文,它就会进入到ESTABLISHED状态
  • ESTABLISHED:表示TCP链接已经成功创建
  • FIN-WAIT-1第一次主动请求关闭链接,等待对方的ACK响应。
  • CLOSE_WAIT:对方发了一个FIN报文给本身,回应一个ACK报文给对方。此时进入CLOSE_WAIT状态。

    • 接下来呢,你须要检查本身是否还有数据要发送给对方,若是没有的话,那你也就能够close()这个SOCKET并发送FIN报文给对方,即关闭本身到对方这个方向的链接
  • FIN-WAIT-2:主动关闭端接到ACK后,就进入了FIN-WAIT-2。在这个状态下,应用程序还有接受数据的能力,可是已经没法发送数据。
  • LAST_ACK:当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK 状态
  • CLOSED:当收到对方的ACK报文后,也就能够进入到CLOSED状态了。
  • TIME_WAIT:表示收到了对方的FIN报文,并发送出了ACK报文。TIME_WAIT状态下的TCP链接会等待2*MSL
  • CLOSING:罕见的状态。表示双方都正在关闭SOCKET链接

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是一个可靠的传输协议,它要保证全部的数据包均可以到达,这须要重传机制来支撑。

重传机制有如下几种:

  • 超时重传
  • 快速重传
  • SACK 方法

滑动窗口能够说是TCP很是重要的一个知识点。TCP的滑动窗口主要有两个做用:

  • 提供TCP的可靠性
  • 提供TCP的流控特性

简略滑动窗口示意图:

详细滑动窗口示意图:

  • #1已收到ack确认的数据
  • #2发还没收到ack的
  • #3在窗口中尚未发出的(接收方还有空间)
  • #4窗口之外的数据(接收方没空间)

接受端控制发送端的图示:

2.4拥塞控制

TCP不是一个自私的协议,当拥塞发生的时候,要作自我牺牲。就像交通阻塞同样,每一个车都应该把路让出来,而不要再去抢路了

拥塞控制主要是四个算法:

  • 1)慢启动,
  • 2)拥塞避免,
  • 3)拥塞发生,
  • 4)快速恢复

拥塞控制的做用:

拥塞的判断:

  • 重传定时器超时
  • 收到三个相同(重复)的 ACK

强烈建议阅读:

参考资料:

3、操做系统

3.1僵尸进程和孤儿进程是什么(区别)

unix/linux环境下

僵尸进程:

  • 父进程建立出子进程,子进程退出了,父进程没有调用waitwaitId获取子进程的信息(状态),子进程的描述符仍在系统中

孤儿进程:

  • 父进程退出,子进程仍在运行中。这些子进程就叫作孤儿进程,孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工做

僵尸进程危害

  • 系统进程表是一项有限资源,若是系统进程表被僵尸进程耗尽的话,系统就可能没法建立新的进程
  • 一个父进程建立了不少子进程,就是不回收,会形成内存资源的浪费

解决僵尸进程的手段:

  • 杀掉父进程,余下的僵尸进程会成为孤儿进程,最后被init进程管理
  • 子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程
  • fork两次:原理是将子进程成为孤儿进程,从而其的父进程变为init进程,经过init进程能够处理僵尸进程

参考资料:

3.2操做系统进程间通讯的方式有哪些?

首先要知道的是:进程和线程的关注点是不同的:

  • 进程间资源是独立的,关注的是通信问题。
  • 线程间资源是共享的,关注的是安全问题。
操做系统进程间通讯的方式有哪些?
  • 管道(pipe):管道是一种半双工的通讯方式,数据只能单向流动,并且只能在具备亲缘关系的进程间使用。进程的亲缘关系一般是指父子进程关系。
  • 有名管道(named pipe):有名管道也是半双工的通讯方式,可是它容许无亲缘关系进程之间的通讯。
  • 消息队列(message queue):消息队列是消息的链表,存放在内核中并由消息队列表示符标示。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限制等缺点。
  • 共享内存(shared memory):共享内存就是映射一段内被其它进程所访问的内存,共享内存由一个进程建立,可是多个进程均可以访问。共享内存是最快的IPC,它是针对其它进程通讯方式运行效率低的而专门设计的。它每每与其它通讯机制。如信号量,配合使用,来实现进程间的同步和通讯。
  • 套接字(socket):套接字也是进程间的通讯机制,与其它通讯机制不一样的是,它能够用于不一样机器间的进程通讯。
  • 信号(signal):信号是一种比较复杂的通讯方式,用于通知接受进程进程某个时间已经发生。
  • 信号量(semaphore):信号量是一个计数器,能够用来控制多个进程对共享资源的访问。

    • 它常做为一种锁的机制,防止某进程正在访问共享资源时,其它进程也访问该资源。所以它主要做为不一样进程或者同一进程之间不一样线程之间同步的手段

3.3操做系统线程间通讯的方式有哪些?

操做系统线程间通讯的方式有哪些?(能够直接理解成:线程之间 同步的方式有哪些)
  • 锁机制:包括互斥锁、条件变量、读写锁
  • 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
  • 信号机制(Signal):相似进程间的信号处理

线程间的通讯目的主要是用于线程同步

参考资料:

扩展阅读:

3.4操做系统进程调度算法有哪些?

操做系统进程调度算法有哪些?
  • 先来先服务算法(FCFS)

    • 谁先来,就谁先执行
  • 短进程/做业优先算法(SJF)

    • 谁用的时间少、就先执行谁
  • 最高响应比优先算法(HRN)

    • 对FCFS方式和SJF方式的一种综合平衡
  • 最高优先数算法

    • 系统把处理机分配给就绪队列中优先数最高的进程
  • 基于时间片的轮转调度算法

    • 每一个进程所享受的CPU处理时间都是一致的
  • 最短剩余时间优先算法

    • 短做业优先算法的升级版,只不过它是抢占式
  • 多级反馈排队算法

    • 设置多个就绪队列,分别赋予不一样的优先级,如逐级下降,队列1的优先级最高

参考笔记:

4、拓展阅读

此部分是看别人的博文已经写得很好了,分享给你们~

4.1ConcurrentHashMap中的扩容是否须要对整个表上锁?

ConcurrentHashMap中的扩容是否须要对整个表上锁?

总结(摘抄)要点:

  • 经过给每一个线程分配桶区间(默认一个线程分配的桶是16个),避免线程间的争用。
  • 经过为每一个桶节点加锁,避免 putVal 方法致使数据不一致。
  • 同时,在扩容的时候,也会将链表拆成两份,这点和 HashMap 的 resize 方法相似。

参考资料:

4.2什么是一致性Hash算法(原理)?

什么是一致性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种):

  1. for遍历两次
  2. 使用hashSet作缓存,记录已遍历过的节点
  3. 使用两个指针,一前一后遍历,总会出现前指针==后指针的状况

参考资料:


判断两个无环链表是否相交,解决方式(2种):

  • 将第一个链表尾部的next指针指向第二个链表,两个链表组成一个链表。

    • 判断这一个链表是否有环,有环则相交,无环则不相交
  • 直接判断两个链表的尾节点是否相等,若是相等则相交,不然不相交

判断两个有环链表是否相交(注:当一个链表中有环,一个链表中没有环时,两个链表必不相交):

  • 找到第一个链表的环点,而后将环断开(固然不要忘记了保存它的下一个节点),而后再来遍历第二个链表,若是发现第二个链表从有环变成了无环,那么他们就是相交的嘛,不然就是不相交的了。

参考资料:

4.5keepAlive含义

  • HTTP协议的Keep-Alive意图在于链接复用,同一个链接上串行方式传递请求-响应数据
  • TCP的KeepAlive机制意图在于保活、心跳,检测链接错误

参考资料:

最后

若是你们有更好的理解方式或者文章有错误的地方还请你们不吝在评论区留言,你们互相学习交流~~~

若是想看更多的 原创技术文章,欢迎你们关注个人 微信公众号:Java3y。Java技术 群讨论:742919422。公众号还有 海量的视频资源哦,关注便可免费领取。

可能感兴趣的连接:

相关文章
相关标签/搜索