分类 |
题目 |
难度系数 |
标准评判(在此定义0-5分内容应该回答成什么样子) |
---|---|---|---|
分类 |
题目 |
难度系数 |
标准评判(在此定义0-5分内容应该回答成什么样子) |
Java基础 | 垃圾回收机制 | ||
线程池原理 | |||
JVM参数含义和使用 | |||
JVM内存分区 | |||
Classloader 如何工作 | |||
Spring IOC | |||
Spring data | |||
Spring AOP | |||
Volitile 原理 | |||
spring 中的设计模式 | |||
Synchronize的机制 | |||
Java8 | |||
Spring MVC | |||
Redis | Redis 支持哪些数据结构 | ||
Redis 两种备份数据的方式和区别,如何使用 | |||
Redis 集群原理如何配置 | |||
Redis 和 Mysql数据的同步问题 | |||
Redis 如何实现分布式锁 | |||
Redis hgetAll 时间复杂度 | |||
Mysql | Mysql的日志类型 | ||
Mysql索引实现原理 | |||
关系型数据库 ACID | |||
MyISAM 和 Innodb区别 | |||
mysql 锁的实现原理-行级锁 | |||
Hibernate乐观锁和悲观锁 | |||
查询优化 | |||
Mysql 隔离级别对锁效果影响 | |||
RabbitMQ | GC | ||
SOA | 原理 | ||
如何实现负载 | |||
服务发现 | |||
服务治理 | |||
降级 | |||
熔断 | |||
常用框架 | |||
分布式数据一致性 | |||
分布式事务 | |||
架构和开放问题 | 搜索引擎实现 | ||
设计秒杀系统 | |||
设计搜索广告系统-竞价排名 | |||
设计分布式数据库 | |||
DRC | |||
多活 |
1.乐观锁和悲观锁的概念,有哪些实际使用的场景?
2.数据库事务有哪些特性?隔离级别是怎么回事?
1.1、数据结构 1.2、网络
参考答案:应用层。
解题思路:基础知识
考察点:OSI七层协议的基础知识 分类:HTTP,基础知识,网络,{校招,社招都可以用} 难度分级:P4
参考答案:
HTTP定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE。这里主要讨论前2种,GET和POST。 GET - 从指定的资源请求数据。
POST - 向指定的资源提交要被处理的数据。
在开始对比前,需要理解1个概念,幂等(idempotent)
在HTTP/1.1规范中幂等性的定义是:
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.
幂等的意味着对同一URL的多个请求应该返回同样的结果。根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的。 所谓安全的意味着该操作用于获取信息而非修改信息。换句话说,GET 请求一般不应产生副作用。 就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态
|
||
|
||
GET |
POST |
|
后退按钮/刷新 |
无害 |
() |
书签 |
可收藏为书签 |
不可收藏为书签 |
缓存 |
能被缓存 |
不能缓存 |
编码类型 |
application/x-www-form-urlencoded |
application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。 |
一、计算机基础
1、 HTTP是网络七层协议中哪一层的协议?
2、Get和Post区别?
4、举出6个http的状态码,502 和 504有什么区别。
5、UDP,TCP是网络七层协议中哪一层的协议,区别是什么,分别适用于什么场景? 参考答案:
6、互联网服务的默认端口是多少?
7、tcp的三次握手,如何用java实现tcp的广播,如果发现网段内的所有集群节点? 1.3、操作系统
1.4、linux 1、Linux Top有哪些重要参数值得关注,这些参数有什么具体含义?
2、Linux上用什么命令看在线日志?
3、如何输出时间到time.txt文件?
4、有一个文本文件source.txt,每行有个字符串,请使用shell命令查找包含“beijing”的行,并将结果保存到文件res ult.txt中
5、查看当前TCP/IP连接的状态和对应的个数?
7、分析apache访问日志,找出访问页面的次数排名前100的ip?
8、符号链接(symbolic link)和硬链接的区别?
1.8、数据库 1、InnoDB 默认什么隔离级别,为什么选用这种级别。选其他的可以么?
2、RR级别下,都有哪些锁?有遇到过死锁么,什么情况下发生的死锁?
3、数据服务端的一些命令(show processlist等等)
4、为什么MySQL的索引要使用B+树而不是其它树形结构?为什么不用B树
6、数据库为什么要使用MVCC,使用MVCC有什么缺点?
7、如何分析慢查询,慢查询的分析步骤?
8、MySQL索引默认实现是用的什么数据结构,为什么采用这种?
9、MySQL联合索引使用是有什么规则?如果对A,B,C做索引,那么SQL语句写成where C=X and B=X and A=X, 是否还能用到该索引?如果SQL语句写成where A=X and B>X and C=X是否还能用到该索引?
10、MySQL引擎MyISAM,InnoDB有什么区别,各有什么特点?
11、从性能上考虑,MySQL InnoDB 表主键如何选择,为什么?
12、MySQL InnoDB默认的事务隔离级别是什么?
13、应用中怎么做到对数据库的读写分离,如何避免主从延迟造成的影响?
14、如何处理组织机构树的联合查询问题?
15、MySQL Explain分析,给面试者一段具体的SQL Explain
16、如何删除一个表的重复数据
17、数据库事物隔离级别,每种的特点;SPRING事物传播与隔离级别的关系,如果配置的。
18、如何优化查询语句,explain每个字段的含义,如果优化OR语句,IN 会用到索引吗?创建索引的顺序
19、每个表的数据大小是否有限制,数据过大会对性能造成影响吗?常见的一些分库分表策略
20、如何实现主从分离,如何解决主从不一致带来的问题?
21、数据库锁,如何防止覆盖更新,如何用数据库模拟队列?
22、什么是乐观锁与悲观锁,如何实现乐观锁?
23、数据库连接池有哪些重要配置参数,分别起到什么作用?
二、Java相关
2.1、Java基础知识
1、为什么重载了equals方法之后需要去重载hashCode方法?
2、重载和覆盖的区别
3、static关键字的用法
4、final finalize finally 关键字都是干什么的?
5、String StringBuffer StringBuilder 区别
6、HashMap的实现原理
7、wait和sleep的区别
9、死锁的四个条件
10、notify和notifyAll的区别
11、Java 泛型的实现原理是什么 ?
12、浅克隆和深克隆?深克隆的方法 ?
13、Integer缓存?Integer比较大小注意问题。==和equals的区别考察
14、装箱和解箱机制?
16、简述一下java的异常体系,什么是受检异常?什么是运行时异常?封装一个API的时候什么情况下抛出异常 ?
17、string常量池的考核
18、Hash冲突,有哪几种常见的解决方法,Java中HashMap用的是哪一种?
19、Java HashMap,已知整个生命周期内不会放入超过100个元素,那么占用内存大小最优且设置完初始值后无需自动扩容 ,该初始值应该设置为多少?
20、Java HashMap在高并发情况下不当使用,可能会导致什么样极端情况,为什么?
21、HashMap/ConcurrentHashMap的数据结构实现,扩容机制,HashMap hash的冲突处理。
22、LinkedHashMap 数据结构实现
23、ArrayList和LinkedList的区别,数据结构实现,扩容机制
24、哈希函数的构造方法常见的有哪几种?
25、HashMap的实现原理(内部数据结构,null key,rehash);为什么说hashMap不是线程安全的。
26、List有哪些实现,实现原理,如何选择实现;是否比较过性能差异?contains方法是怎么比较对象的?
27、如何拷贝数组,怎样效率最高?为什么?
2.2、JVM
1、 Jvm堆内存区,有两个S区有什么作用?
2、有遇到过OOM么,什么情况,怎么发现的,怎么查原因的?
3、内存分配策略
4、线程内存和主内存是如何交互的?
5、线上环境JVM参数Xms Xmx是如何设置的, 如果大小是一至,为什么这样设置?
6、如何定位一个CPU Load过高的Java线程?
7、JmapDump的文件大小和MAT分析工具里显示的大小不一致一般是什么原因导致的?
8、如何在Jmap未响应的情况下Dump出内存?
9、说出5个JVM的参数以及含义,怎么样配置这样参数?
10、JVM的一些健康指标和经验值,如何配置最优?
11、对象存活算法,常见的有哪几种,JAVA采用的是哪种?
12、JVM新生代ParNew用的是什么垃圾收集算法?
13、JVM垃圾收集复制算法中,Eden:Form:To,为什么是8:1:1,而不是1:1:1?
14、JVM老年代CMS用的是什么垃圾收集算法?
15、young gc和full gc触发条件
16、垃圾回收器种类,垃圾回收扫描算法(root扫描),回收算法(复制,标记清除,标记整理)
17、 cms回收器的标记过程,内存碎片问题
18、GC Log分析,给面试者一段具体GC Log
20、JVM垃圾收集在ParNew+CMS条件下,哪些情况下会让JVM认为产生了一次FULL GC?
21、如何查看StringPool大小?
22、JmapDump的文件中是否包括StringPool?
2.3、 多线程
3、多次调用线程的start方法会怎么样?
4、线程sleep()和yield()的区别是什么?
5、线程同步问题
6、wait()和notify(),wait和sleep的区别
7、IO密集型和CPU密集型与线程池大小的关系
8、ThreadLocal 作用和实现机制
9、java线程池corePoolSize,maxPoolSize,queueCapacity这些参数的意义,如何考虑这些参数的设置
10、ThreadLocal是什么,有什么典型的应用场景?
11、考虑设计一个计数器程序,场景一,一个线程写,多个线程读;场景二,多个线程写,多个线程读。分别应对这2种 场景设计一个计数器程序 ,要保证线程安全
12、多线程的使用场景,为了解决什么样的问题。不适用于什么场景
13、线程池的实现原理
14、常见的线程工具(同步器、线程安全集合类、原子类),什么场景下使用
15、常见的线程状态,以及相互转换图;WAITING和BLOCK的区别
16、常见的同步方式 synchronized 和 lock 如何选择
17、死锁的几种场景,如何避免死锁
18、利用缓存机制优化一个复杂计算程序
19、Java方法体中用到了多线程,使用了ThreadPool,但是方法体内程序员没有显式调用ShutDown关闭线程池, 那么该方法执行结束后,JVM 是否能自动的关闭线程池,销毁线程?
20、ThreadPool中线程是如何做到重用的?
历史 |
||
对数据长度的限制 |
是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。 |
无限制。 |
对数据类型的限制 |
只允许 ASCII 字符。 |
|
安全性 |
与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。 在发送密码或其他敏感信息时绝不要使用 GET ! |
POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。 |
可见性 |
数据在 URL 中对所有人都是可见的。 |
数据不会显示在 URL 中。 |
解题思路:HTTP基础知识,从面向数据提交方式、安全性等方面进行对比,如果能阐述幂等性更好 考察点:幂等性,GET和POST信息的提交方式 分类:网络应用层,HTTP基础知识{校招,社招都可以用} 3、描述一下一次HTTP请求从请求到返回的过程,越详细越深入越好。 (或者,访问一个url 都经历过了哪些事情,越详细越好。) 参考答案: |
||
1)把URL分割成几个部分:协议、网络地址、资源路径。 浏览器缓存 – 浏览器会缓存DNS记录一段时间。 有趣的是,操作系统没有告诉浏览器储存DNS记录的时间,这样不同浏览器会储存个自固定的一个时间(2分钟到30分钟不等)。 3)如果地址不包含端口号,根据协议的默认端口号确定一个。 ,,, , 例如:www.guokr.com 不包含端口号,http协议默认端口号是80。 如果你输入的url是http://www.guokr.com:8080/ ,那表示不使用默认的端口号,而使用指定的端口号8080。 4)向2和3确定的IP和端口号发起网络连接。 例如:向111.13.57.142的80端口发起连接 5)根据http协议要求,组织一个请求的数据包,里面包含大量请求信息,包括请求的资源路径、你的身份 例如:用自然语言来表达这个数据包,大概就是:请求 /question/554991/ ,我的身份是xxxxxxx。 6)服务器响应请求,将数据返回给浏览器。数据可能是根据HTML协议组织的网页,里面包含页面的布局、文字。数据也可能是图片、脚本程序等 。现在你可以用浏览器的“查看源代码”功能,感受一下服务器返回的是什么东东。如果资源路径指示的资源不存在,服务器就会返回著名的404 错误。 7)如果(6)返回的是一个页面,根据页面里一些外链的URL,例如图片的地址,按照(1)-(6)再次获取。 |
8)开始根据资源的类型,将资源组织成屏幕上显示的图像,这个过程叫渲染,网页渲染是浏览器最复杂、最核心的功能。
状态码范围 |
作用 |
100-199 |
|
200-299 |
用于表示请求成功。 |
300-399 |
|
400-499 |
用于指出客户端的错误。 |
500-599 |
用于支持服务器错误。 |
TCP |
UDP |
|
是否连接 |
面向连接 |
面向非连接 |
传输可靠性 |
可靠 |
不可靠 |
应用场合 |
传输大量数据 |
少量数据 |
速度 |
慢 |
快 |
8)开始根据资源的类型,将资源组织成屏幕上显示的图像,这个过程叫渲染,网页渲染是浏览器最复杂、最核心的功能。
9)将渲染好的页面图像显示出来,并开始响应用户的操作。
,,
即使基本步骤本身也有很复杂的子步骤,TCP/IP、DNS、HTTP、HTML:每一个都可以展开成庞大的课题,而浏览器的基础——操作系统、编译 器、硬件等更是一个比一个复杂。
,,,,
解题思路:从一个请求的时间上顺序进行阐述,涉及多个过程,最好能做深入 考察点:网络综合知识 分类:基础知识,网络{校招,社招都可以用}
难度分级:P4,P5,P6
参考答案:
大类区分见下表
具体每个码的含义见右边的链接->HTTP状态码大全
502 Bad Gateway:作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
504 Gateway Time-out:作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LD AP)或者辅助服务器(例如DNS)收到响应。
502 Bad Gateway:Tomcat没有启动起来
504 Gateway Time-out: Nginx报出来的错误,一般是Nginx做为反向代理服务器的时候,所连接的应用服务器譬如Tomcat无相应导致的 解题思路:基础知识
考察点:HTTP的基础知识,要求能记住工作中常见的几个错误码
分类:网络应用层,HTTP,基础知识{社招}
难度分级:P5
传输层。 在TCP/IP模型中,传输层的功能是使源端主机和目标端主机上的对等实体可以进行会话。
在传输层定义了两种服务质量不同的协议。即:传输控制协议TCP(transmission control protocol)和用户数据报协议UDP(user datagram protocol)。
TCP协议是一个面向连接的、可靠的协议。它将一台主机发出的字节流无差错地发往互联网上的其他主机。 需要三次握手建立连接,才能进行数据传输。在发送端,它负责把上层传送下来的字节流分成报文段并传递给下层。
在接收端,它负责把收到的报文进行重组后递交给上层。TCP协议还要处理端到端的流量控制,以避免缓慢接收的接收方没有足够的缓冲区接收发
在接收端,它负责把收到的报文进行重组后递交给上层。TCP协议还要处理端到端的流量控制,以避免缓慢接收的接收方没有足够的缓冲区接收发 送方发送的大量数据。 UDP协议是一个不可靠的、无连接协议,不与对方建立连接,而是直接就把数据包发送过去。主要适用于不需要对报文进行排序和流量控制的 场合。 UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境。比如,我们经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常, 其 实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是 通的。
解题思路:基础知识,从面向连接、可靠性、应用场合上进行分析对比 考察点:七层协议中传输层的基础知识,着重从TCP vs UDP的区别上考察 分类:七层协议,基础知识,网络,{校招,社招都可以用} 难度分级:P4,P5
参考答案:
HTTP 80
HTTP 80 SMTP 25 POP3 110 FTP 21 20 TELNET 23
解题思路:
考察点:网络协议,端口 分类:网络应用层,基础知识{校招,社招都可以用} 难度分级:P5
1.4、linux
1、Linux Top有哪些重要参数值得关注,这些参数有什么具体含义?
参考答案:
Linux的top命令详解见http://www.2cto.com/os/201209/157960.html 解题思路:不同水平的面试人员有不同层次的理解,面试官应视其回答情况 酌情给分 考察点:Linux运行情况的查看、top命令的使用熟练程度 分类:Linux基本操作{校招,社招都可以用}
难度分级:P4
参考答案:
Linux 日志都以明文形式存储,所以用户不需要特殊的工具就可以搜索和阅读它们。 还可以编写脚本,来扫描这些日志,并基于它们的内容去自动执行某些功能。
Linux 日志存储在 /var/log 目录中。这里有几个由系统维护的日志文件,但其他服务和程序也可能会把它们的日志放在这里。 大多数日志只有root账户才可以读,不过修改文件的访问权限就可以让其他人可读。 可以用cat、head、tail等查看,用grep搜索过滤,用cut取字段(列数据),更高级的可以用awk和sed重排日志。 可以用cat、head、tail等查看,用grep搜索过滤,用cut取字段(列数据),更高级的可以用awk和sed重排日志。 解题思路:日志文件的格式多是文本文件,从文本文件的处理方式的考虑 考察点:日志的存储,Linux查看、搜索文本文件的方式,坑在直接用VI看,如果稍有经验的人这么做,那么基本可以送走了 分类:Linux基本操作{校招,社招都可以用}
难度分级:P4
参考答案: 解题思路:重定向的应用
考察点: Linux命令输出重定向、简单的Linux命令 分类:Linux基本操作{校招,社招都可以用} 难度分级:P4
考察点: Linux命令输出重定向、简单的Linux命令 分类:Linux基本操作{校招,社招都可以用} 难度分级:P4
参考答案:
grep -i beijing source.txt > result.txt 解题思路:用grep来对文本文件搜索,注意-i选项用来忽略大小写 考察点: Linux命令输出重定向、grep简单应用 分类:Linux基本操作{校招,社招都可以用}
难度分级:P4
参考答案:
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
解题思路:用netstat来查看连接和端口,用awk进行统计
考察点: netstat和awk的应用 分类:Linux组合操作{校招,社招都可以用} 难度分级:P5
awk '{print $1}' localhost_access_log.txt | sort | uniq -c | sort -n -k 1 -r | head -n 100
解题思路:用awk或者cut来取文本中的第一列,再用sort排序,uniq去重,数字排序,最后输出前100名 考察点: awk、sort、head等文本处理工具组合的应用
分类:Linux组合操作{社招}
难度分级:P5
参考答案:
date >> time.txt
硬链接(hard links): 为文件创建了额外的条目。使用时,与文件没有区别;删除时,只会删除链接,不会删除文件;
硬链接(hard links): 为文件创建了额外的条目。使用时,与文件没有区别;删除时,只会删除链接,不会删除文件; 硬链接的局限性: 1. 不能引用自身文件系统以外的文件,即不能引用其他分区的文件;2. 无法引用目录;
操作: ln file link, 只能link文件;
符号链接(symbolic links): 克服硬链接的局限性,类似于快捷方式,使用与硬链接相同. 如果先删除文件,则会成为坏链接(broken),ls会以不同颜色(Ubuntu, 红色)显示; 操作: ln -s item link,可以link文件和目录;
解题思路:hard link和soft link的区别,结合i-node的知识 考察点: i-node,文件链接 分类:Linux文件系统基本概念{校招,社招} 难度分级:P4
1.5、web 1.6、安全 1.7、设计模式
参考答案: http://www.cnblogs.com/vinchen/archive/2012/11/19/2777919.html 解题思路:数据库事务
考察点:数据库事务 分类:数据库事务{校招,社招} 难度分级:P4
参考答案: http://hedengcheng.com/?p=771
解题思路:数据库事务 考察点:数据库事务 分类:数据库事务{校招,社招} 难度分级:P4
a. show tables或show tables from database_name; -- 显示当前数据库中所有表的名称
b. show databases; -- 显示mysql中所有数据库的名称
c. show columns from table_name from database_name; 或show columns from database_name.table_name; -- 显示表中列名称
d. show grants for user_name; -- 显示一个用户的权限,显示结果类似于grant 命令
e. show index from table_name; -- 显示表的索引
f. show status; -- 显示一些系统特定资源的信息,例如,正在运行的线程数量
g. show variables; -- 显示系统变量的名称和值
h. show processlist; -- 显示系统中正在运行的所有进程,也就是当前正在执行的查询。大多数用户可以查看他们自己的进程,但是如果他们拥有process权限,就可以查 看所有人的进程,包括密码。
i. show table status; -- 显示当前使用或者指定的database中的每个表的信息。信息包括表类型和表的最新更新时间
j. show privileges; -- 显示服务器所支持的不同权限
k. show create database database_name; -- 显示create database 语句是否能够创建指定的数据库
l. show create table table_name; -- 显示create database 语句是否能够创建指定的数据库
m. show engies; -- 显示安装以后可用的存储引擎和默认引擎。
n. show innodb status; -- 显示innoDB存储引擎的状态
o. show logs; -- 显示BDB存储引擎的日志
p. show warnings; -- 显示最后一个执行的语句所产生的错误、警告和通知
q. show errors; -- 只显示最后一个执行语句所产生的错误
r. show [storage] engines; --显示安装后的可用存储引擎和默认引擎
s. show procedure status --显示数据库中所有存储的存储过程基本信息,包括所属数据库,存储过 程名称,创建时间等
t. show create procedure sp_name --显示某一个存储过程的详细信息 解题思路: 考察点: mysql 分类:数据库,硬技能{校招,社招} 难度分级:P4、P5
参考答案:
为什么不用B树?:因为B树的所有节点都是包含键和值的,这就导致了每个几点可以存储的内容就变少了,出度就少了,树的高度会增高,查询的 时候磁盘I/O会增多,影响性能。由于B+Tree内节点去掉了data域,因此可以拥有更大的出度,拥有更好的性能。
解题思路:Mysql 索引数据结构
考察点: Mysql索引数据结构,B+树 B-树 分类:Mysql、数据结构{校招,社招} 难度分级:P4,P5
5、为什么InnoDB中表的主键最好要自增?
InnoDB使用聚集索引,数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的 各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(Inno DB默认为15/16),则开辟一个新的页(节点)。如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置, 当一页写满,就会自动开辟一个新的页。这样就会形成一个紧凑的索引结构,近似顺序填满。由于每次插入时也不需要移动已有数据,因此效率很 高,也不会增加很多开销在维护索引上。
如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置,此 时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增 加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。
因此,只要可以,请尽量在InnoDB上采用自增字段做主键。 解题思路:InnoDB 主键选择 考察点:InnoDB 索引数据结构,Mysql应用技能 分类:Mysql{校招,社招}
难度分级:P4,P5
参考答案:
Multi-Version Concurrency Control 多版本并发控制,因为锁机制是一种预防性的,读会阻塞写,写也会阻塞读,当锁定粒度较大,时间较长时并发性能就不会太好;而MVCC是一种 后验性的,读不阻塞写,写也不阻塞读,等到提交的时候才检验是否有冲突,由于没有锁,所以读写不会相互阻塞,从而大大提升了并发性能。
缺点:通过MVCC机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据,是不及时的数据,不是数据库当前的数据!这在一些对于 数据的时效特别敏感的业务中,就很可能出问题。
解题思路:MVCC
考察点: mysql 锁机制与MVCC 分类:Mysql、锁机制、MVCC{校招,社招} 难度分级:P5
参考答案: 慢查询优化基本步骤
0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE 1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分 别查询,看哪个字段的区分度最高
2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
3.order by limit 形式的sql语句让排序的表优先查
3.order by limit 形式的sql语句让排序的表优先查 4.了解业务方使用场景 5.加索引时参照建索引的几大原则 6.观察结果,不符合预期继续从0分析
参考:http://tech.meituan.com/mysql-index.html 解题思路: 考察点:mySql查询优化 分类:数据库,硬技能{校招,社招}
难度分级:P5
B+树。
索引也是磁盘上的,磁盘的I/O存取的消耗是比内存高出几个数量级的,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数,所以要尽量降 低树的高度。要降低树的高度,因此用多分支的树,并且要树的每层的节点尽量的多,B+树将一个节点的大小设为等于一个页,这样每个节点只需 要一次I/O就可以完全载入,由于B+Tree内节点去掉了data域,因此可以拥有更大的出度,拥有更好的性能。
参考:http://www.marksaas.com/2014/04/mysql%E7%B4%A2%E5%BC%95%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86.html 解题 思路:Mysql 索引数据结构
考察点: Mysql索引数据结构,B+树 B-树
分类:Mysql、数据结构{校招,社招}
难度分级:P4,P5
参考答案:
where C=X and B=X and A=X能用到该索引,因为=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。
where A=X and B>X and C=X可以用到该索引,但C是用不到索引的,因为mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配。
解题思路:联合索引最左前缀匹配原则
考察点: 是否对联合索引的匹配原则,以及所以的数据结构有过了解 分类:Mysql索引基础知识{校招,社招}
难度分级:P4,P5
参考答案: MySQL有多种存储引擎,MyISAM和InnoDB是其中常用的两种。这里介绍关于这两种引擎的一些基本概念(非深入介绍)。
MyISAM是MySQL的默认存储引擎,基于传统的ISAM类型,支持全文搜索,但不是事务安全的,而且不支持外键。每张MyISAM表存放在三个文 件中:frm 文件存放表格定义;数据文件是MYD (MYData);索引文件是MYI (MYIndex)。
InnoDB是事务型引擎,支持回滚、崩溃恢复能力、多版本并发控制、ACID事务,支持行级锁定(InnoDB表的行锁不是绝对的,如果在执行一个S QL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,如like操作时的SQL语句),以及提供与Oracle类型一致的不加锁读取方式。I nnoDB存储它的表和索引在一个表空间中,表空间可以包含数个文件。
主要区别:
MyISAM是非事务安全型的,而InnoDB是事务安全型的。 MyISAM锁的粒度是表级,而InnoDB支持行级锁定。 MyISAM支持全文类型索引,而InnoDB不支持全文索引。 MyISAM相对简单,所以在效率上要优于InnoDB,小型应用可以考虑使用MyISAM。 MyISAM表是保存成文件的形式,在跨平台的数据转移中使用MyISAM存储会省去不少的麻烦。 MyISAM表是保存成文件的形式,在跨平台的数据转移中使用MyISAM存储会省去不少的麻烦。 InnoDB表比MyISAM表更安全,可以在保证数据不会丢失的情况下,切换非事务表到事务表(alter table tablename type=innodb)。
应用场景: MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。
InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB, 这样可以提高多用户并发操作的性能。
解题思路:MyISAM和InnoDB引擎区别 考察点: MyISAM和InnoDB引擎的了解 分类:Mysql
难度分级:P5
自增主键
InnoDB使用聚集索引,数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的 各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(Inno DB默认为15/16),则开辟一个新的页(节点)。如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置, 当一页写满,就会自动开辟一个新的页。这样就会形成一个紧凑的索引结构,近似顺序填满。由于每次插入时也不需要移动已有数据,因此效率很 高,也不会增加很多开销在维护索引上。
如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置,此 时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增 加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。
因此,只要可以,请尽量在InnoDB上采用自增字段做主键。 解题思路:InnoDB 主键选择 考察点:InnoDB 索引数据结构,Mysql应用技能 分类:Mysql
参考答案:
Repeatable Read(可重复读) 解题思路:Repeatable Read(可重复读) 考察点: 数据库事务了解 分类:Mysql、事务
难度分级:P4,P5
解题思路: 考察点: 分类: 难度分级:P5
,
http://blog.csdn.net/monkey_d_meng/article/details/6647488 http://blog.csdn.net/biplusplus/article/details/7433625 解题思路:
http://blog.csdn.net/monkey_d_meng/article/details/6647488 http://blog.csdn.net/biplusplus/article/details/7433625 解题思路: 考察点:
分类: 难度分级:P5
参考答案:
http://wiki.sankuai.com/x/-JMRBQ
解题思路: 考察点:
分类: 难度分级:P5
参考答案:
CREATE TABLE `poi_menu_test` ( `id` bigint(30) NOT NULL AUTO_INCREMENT COMMENT 'ID', `poi_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'id', `name` varchar(64) NOT NULL DEFAULT '' COMMENT '', PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=17621402 DEFAULT CHARSET=utf8 COMMENT='poi';
delete pmt from poi_menu_test pmt inner join ( select id,poi_id,name from poi_menu_test group by poi_id,name having count(*) > 1 )tmp on tmp.poi_id = pmt.poi_id and tmp.name = pmt.name and tmp.id <> pmt.id;
解题思路: 考察点: 分类:社招 难度分级:P5
数据事务的四种隔离级别
,,,
隔离级别
未提交读(Read uncommitted) 已提交读(Read committed) 可重复读(Repeatable read) 可串行化(Serializable ) 脏读(Dirty Read)
可能 不可能 不可能 不可能 不可重复读(NonRepeatable Read)
可能 可能 不可能 不可能 幻读(Phantom Read)
可能 可能 可能 不可能
未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据 提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存 在幻象读
串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞 spring的事务隔离级别
ISOLATION_DEFAULT:使用数据库默认的隔离级别。 ISOLATION_READ_UNCOMMITTED:允许读取改变了的还未提交的数据,可能导致脏读、不可重复读和幻读。
ISOLATION_READ COMMITTED:允许并发事务提交之后读取,可以避免脏读,可能导致重复读和幻读。 ISOLATION_REPEATABLE_READ:对相同字段的多次读取结果一致,可导致幻读。 ISOLATION_SERIALIZABLE:完全服从ACID的原则,确保不发生脏读、不可重复读和幻读。 可以根据自己的系统对数据的要求采取适应的隔离级别,因为隔离牵涉到锁定数据库中的记录,对数据正性要求越严格,并发的性能也越差。 spring的事务传播行为
spring事务的传播行为说的是当一个方法调用另一个方法时,事务该如何操作。 PROPAGATION_MANDATORY:该方法必须运行在一个事务中。如果当前事务不存在则抛出异常。
PROPAGATION_NESTED:如果当前存在一个事务,则该方法运行在一个嵌套的事务中。被嵌套的事务可以从当前事务中单独的提交和回滚。如
PROPAGATION_NESTED:如果当前存在一个事务,则该方法运行在一个嵌套的事务中。被嵌套的事务可以从当前事务中单独的提交和回滚。如 果当前不存在事务,则开始一个新的事务。各厂商对这种传播行为的支持参差不齐,使用时需注意。 PROPAGATION_NEVER:当前方法不应该运行在一个事务中。如果当前存在一个事务,则抛出异常。 PROPAGATION_NOT_SUPPORTED:当前方法不应该运行在一个事务中。如果一个事务正在运行,它将在该方法的运行期间挂起。 PROPAGATION_REQUIRED:该方法必须运行在一个事务中。如果一个事务正在运行,该方法将运行在这个事务中。否则,就开始一个新的事务 。 PROPAGATION_REQUIRES_NEW:该方法必须运行在自己的事务中。它将启动一个新的事务。如果一个现有的事务正在运行,将在这个方法的运 PROPAGATION_REQUIRES_NEW:该方法必须运行在自己的事务中。它将启动一个新的事务。如果一个现有的事务正在运行,将在这个方法的运 行期间挂起。 PROPAGATION_SUPPORTS:当前方法不需要事务处理环境,但如果一个事务已经在运行的话,这个方法也可以在这个事务里运行。
配置方法:
PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED,readOnly PROPAGATION_REQUIRED,ISOLATION_READ_UNCOMMITTED
解题思路: 考察点:
分类: 数据库,spring 难度分级:P5
参考答案:
explain每个字段含义:Mysql explain学习总结 or语句:where语句里如果带有or条件,是可以用到索引,前提是有针对or条件所有字段的单独索引 in会用到索引
优化or语句:or条件建立单独索引,用union替代
解题思路:
考察点: mysql 索引,优化 分类:mysql 难度分级:P5
参考答案: mysql单表大小限制可以参考这篇文章:http://database.51cto.com/art/201011/234308.htm
这里引用一个问题为什么要分库分表呢?MySQL处理不了大的表吗? 其实是可以处理的大表的.我所经历的项目中单表物理上文件大小在80G多,单表记录数在5亿以上,而且这个表 属于一个非常核用的表:朋友关系表.
但这种方式可以说不是一个最佳方式. 因为面临文件系统如Ext3文件系统对大于大文件处理上也有许多问题. 这个层面可以用xfs文件系统进行替换.但MySQL单表太大后有一个问题是不好解决: 表结构调整相关的操作基 本不在可能.所以大项在使用中都会面监着分库分表的应用.
从Innodb本身来讲数据文件的Btree上只有两个锁, 叶子节点锁和子节点锁,可以想而知道,当发生页拆分或是添加 新叶时都会造成表里不能写入数据. 关于分表分库策略:
http://my.oschina.net/cmcm/blog/175104
解题思路: 考察点: mysql 分类:mysql 难度分级:P5 P6
参考:数据库读写分离相关调研 解题思路: 考察点: MySQL
分类:MySQL 难度分级:P5 P6
参考答案:
覆盖更新可以用for update和 where 要更新的字段=更新之前的状态,判断影响记录数来实现。模拟队列需要考虑类型,优先级字段,同时用锁来避免重复同一条记录
解题思路:
考察点: MySQL,数据库 分类:数据库 难度分级:P5 P6
悲观锁
,(,),, ,,(,, ,)
乐观锁
,, ,,
而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本 信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
--补充, 当主键采用数据库表生成时(GenerationType.TABLE),采用乐观锁好还是采用悲观锁好? 这个要考虑决具体的策略?
一般来讲,我们会根据数据生长速度(考察点,需要考虑)来申请一定数量的主键ID,比如100个,这样可以最大限度的增加主键生成的效率,减少不必要的 数据库交互
这样即使在集群环境下,表访问的竞争压力并不大,因此采用悲观锁就可以;而且乐观锁并不一定能够防止数据的"脏写",会导致主键重复的情况发生。 要说明的是,MVCC的实现没有固定的规范,每个数据库都会有不同的实现方式,这里讨论的是InnoDB的MVCC。
参考:Innodb中的事务隔离级别和锁的关系 解题思路: 考察点: 悲观锁 乐观锁
分类: 数据库
难度分级:P5
标准答案:
C3P0 拥有比 DBCP 更丰富的配置属性,通过这些属性,可以对数据源进行各种有效的控制: acquireIncrement :当连接池中的连接用完时, C3P0 一次性创建新连接的数目; acquireRetryAttempts :定义在从数据库获取新连接失败后重复尝试获取的次数,默认为 30 ; acquireRetryDelay :两次连接中间隔时间,单位毫秒,默认为 1000 ;
autoCommitOnClose :连接关闭时默认将所有未提交的操作回滚。默认为 false ;
automaticTestTable : C3P0 将建一张名为 Test 的空表,并使用其自带的查询语句进行测试。如果定义了这个参数,那么属性 preferredTestQuery 将被忽略。你 不能在这张 Test 表上进行任何操作,它将中为 C3P0 测试所用,默认为 null ;
breakAfterAcquireFailure :获取连接失败将会引起所有等待获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调 用 getConnection() 的时候继续尝试获取连接。如果设为 true ,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认为 false ;
checkoutTimeout :当连接池用完时客户端调用 getConnection() 后等待获取新连接的时间,超时后将抛出 SQLException ,如设为 0 则无限期等待。单位毫秒,默认为 0 ;
connectionTesterClassName : 通过实现 ConnectionTester 或 QueryConnectionTester 的类来测试连接,类名需设置为全限定名。默认为 com.mchange.v2.C3P0.impl.DefaultConnectionTester ;
idleConnectionTestPeriod :隔多少秒检查所有连接池中的空闲连接,默认为 0 表示不检查;
initialPoolSize :初始化时创建的连接数,应在 minPoolSize 与 maxPoolSize 之间取值。默认为 3 ;
maxIdleTime :最大空闲时间,超过空闲时间的连接将被丢弃。为 0 或负数则永不丢弃。默认为 0 ;
var flag=false; function checkForm(){
if (flag==true){ return false;
} flag=true; document.form1.submit();
}
maxIdleTime :最大空闲时间,超过空闲时间的连接将被丢弃。为 0 或负数则永不丢弃。默认为 0 ;
maxPoolSize :连接池中保留的最大连接数。默认为 15 ;
maxStatements : JDBC 的标准参数,用以控制数据源内加载的 PreparedStatement 数量。但由于预缓存的 Statement 属 于单个 Connection 而不是整个连接池。所以设置这个参数需要考虑到多方面的因素,如果 maxStatements 与 maxStatementsPerConnection 均为 0 ,则缓存被关闭。默认为 0 ;
maxStatementsPerConnection :连接池内单个连接所拥有的最大缓存 Statement 数。默认为 0 ;
numHelperThreads : C3P0 是异步操作的,缓慢的 JDBC 操作通过帮助进程完成。扩展这些操作可以有效的提升性能,通过多线程实现多个操作同时被执行。默认为 3 ;
preferredTestQuery :定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个参数能显著提高测试速度。测试的表必须在初始数据源的时候就存在。默认 为 null ;
propertyCycle : 用户修改系统配置参数执行前最多等待的秒数。默认为 300 ;
testConnectionOnCheckout :因性能消耗大请只在需要的时候使用它。如果设为 true 那么在每个 connection 提交的时候都 将校验其有效性。建议使用 idleConnectionTestPeriod 或 automaticTestTable
等方法来提升连接测试的性能。默认为 false ;
testConnectionOnCheckin :如果设为 true 那么在取得连接的同时将校验连接的有效性。默认为 false 。
解题思路:同答案
解题思路:同答案
考察点: 数据库连接池 分类:Spring,Mysql {社招} 难度分级:P5,P6
A:Hash的时候需要保证equals的对象映射到同一个位置
静态方法和静态代码块 static和非static的区别,一般什么情况下会使用,怎么去用; 什么时候执行;
加分 —— 实例变量,静态变量,构造函数、父类相对变量的执行过程。
StringBuffer和StringBuilder是线程安全问题,String和StringBuilder是效率以及内存分配问题。 加分1: String和StringBuilder在编译优化之后结果基本一致;
加分2: String在循环中操作,回导致声明很多的StringBuilder,因此禁止这种操作;
基本:底层数据结构,冲突解决(Hash值映射到同一个位置——List,再次Hash) 加分:链表解决冲突的情况下如何优化速度?List长度超过一个值,B Tree。 加分:ConcurrentHashMap的实现——Segment。 加分:ConcurrentModificationException异常发生的原因
前者要求必须先获得锁才能调用,后者不需要。前者调用后会释放锁(进入等待池),后者不存在释放问题。
8、synchronized关键字修饰静态方法和实例方法的区别
加锁对象不一样。 加分:和volatile关键字的区别?:volatile只管可见性,synchronized同时保证互斥性
1) 互斥条件:一个资源每次只能被一个进程使用。(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
除唤醒线程外,前者调用后其余线程还在等待池,后者其余线程进入锁池(可以主动竞争锁)
基本:概念用法,T ? extends 加分:泛型擦除,如下:编译报错还是运行报错
public void test(List li){ } public void test(List ls){ }
http://www.itzhai.com/java-based-notebook-the-object-of-deep-and-shallow-copy-copy-copy-implement-the-cloneable-interface-se rializing-deep-deep-copy.html
Integer是有缓冲池的,java.lang.Integer.valueOf(int)方法默认情况下如果参数在-128到127之间,则返回缓存中的对象,否则返回new Integer(int)。java使用该机制是为了达到最小化数据输入和输出的目的,这是一种优化措施,提高效率
其他的包装器:
Boolean: (全部缓存) Byte: (全部缓存) Character ( <=127 缓存)
Short
Long
Float
Doulbe (没有缓存)
(-128~127 缓存) (-128~127 缓存)
(没有缓存)
可以设置系统属性 java.lang.Integer.IntegerCache.high 修改缓冲区上限,默认为127。参数内容应为大于127的十进制数形式的字符串,否则将被忽略。取值范围为127-Long.MAX_VALUE,但是用时将 强转为int。当系统中大量使用Integer时,增大缓存上限可以节省小量内存。
区别“==”和equals():“==”是比较两个对象是不是引用自同一个对象。 “equals()”是比较两个对象的内容。
http://developer.51cto.com/art/201203/325314.htm
15、java的类加载器体系结构和双亲委托机制
http://blog.csdn.net/lovingprince/article/details/4317069
http://blog.csdn.net/lovingprince/article/details/4317069 加分:jetty or tomcat的类加载机制
String s1 = new String("hello");
String s2 = "hello"; 区别
http://blog.sina.com.cn/s/blog_5203f6ce0100tiux.html
参考答案:
(1)开放定址法; (2)拉链法;http://www.cnblogs.com/jillzhang/archive/2006/11/03/548671.html Java中HashMap使用的是拉链法。 解题思路:基础知识
考察点:Hash冲突,HashMap的底层数据结构实现
分类:数据结构,Java集合框架
难度分级:P4
参考答案:
如果默认使用H ashMap内置的负载因子loadFactor为0.75。鉴于HashMap初始化设置大小为2的n次方,则100/0.75=133. 大于133的最小2的n次方为256个。
解题思路:基础知识
考察点: 考察HashMap的负载因子以及构造函数的理解
分类:Java集合框架{校招,社招} 难度分级:P4
在并发的多线程使用场景中,在resize扩容的时候,使得HashMap形成环链,造成死循环,CPU飙升至100%。可以举例子说明。
参考链接:http://wiki.sankuai.com/x/oUl9BQ 解题思路: 考察点:HashMap的并发性 分类:{校招,社招}
答案参考前面。 补充:扩容机制考察扩容时机,扩容容量变化机制,扩容具体实现步骤-源码resize() 函数。 解题思路: 考察点:HashMap/ConcurrentHashMap的底层实现
分类:{校招,社招}
难度分级:P4,P5
参考答案:
参考答案:
首先搞清楚HashMap得实现;然后重点考察和HashMap的区别。 LinkedHashMap实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可 以是插入顺序或者是访问顺序。最好画个图解释下。Entry对象在HashMap的时候包含key,value,hash值,以及一个next;而在LinkedHashM ap中新增了before和after。
ap中新增了before和after。
解题思路:基础知识 考察点:HashMap和LinkedHashMap 的数据结构的区别 分类:{校招,社招}
难度分级:P4,P5
参考答案:
(1) ArrayList是实现了基于动态数组的数据结构,LinkedList基于双向循环链表的数据结构。 (2) 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。 (3) 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 (4) 查找操作indexOf,lastIndexOf,contains等,两者差不多。
(5) 随机查找指定节点的操作get,ArrayList速度要快于LinkedList. 当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在 一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。
扩容: 针对ArrayList,在新增的时候,容量不够就需要扩容,2倍。
解题思路:基础知识
考察点:ArrayList和LinkedList的区别,ArrayList的扩容
分类:{校招,社招}
难度分级:P4
参考答案:
(1)直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a·key + b为散列函数。若其中H(key)中已经有值了,就往下一个找,直到H(key)中没有值了,就放进去。 (2) 数字分析法:就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。 (3)平方取中法:取关键字平方后的中间几位作为散列地址。
(4) 折叠法:将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(去除进位)作为散列地址。 (5)随机数法:选择一随机函数,取关键字的随机值作为散列地址,通常用于关键字长度不同的场合。 (6)除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p,p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同 义词。
解题思路:基础知识 考察点:哈希函数的构造方法 分类:数据结构 难度分级:P4
参考答案:
(1)内部数据结构实现:数组+链表 (最好画个图能解释清楚) (2)key值不能重复,只能put一个key为null的键值对。可以更深层次考察对put(null,value)以及get(null)的 理解。 (3)HashMap在put时,经过了两次hash,一个是JDK自带的对对象key的hash,然后再对结果使用HashMap内部函数hash(int h);hash(int h)方法根据key的hashCode重新计算一次散列。可以更深入考察对hash(int h)以及indexFor(int h, int length)两个函数的理解。 (4)在put时如果空间不够就需要扩容resize(),考察扩容过程--重新计算复制。 (5)在并发的多线程使用场景中,使用HashMap形成环链,造成死循环,CPU飙升至100%。例子见链接。 http://wiki.sankuai.com/pages/viewpage. action?pageId=89609604
解题思路:基础知识
考察点: 考察HashMap的底层实现远离
分类:Java集合框架{校招,社招}
难度分级:P4
参考答案:
(1)List的直接实现是两个抽象类,AbstactList和AbstractSequentialList.其中,AbstractList为随即访问(如数组)实现方案提供尽可能的封装 ,AbstractSequentialList为连续访问(如链表)实现方案提供了尽可能的封装。ArrayList,直接父类是AbstractList,数据结构是大小可变的数组, 它不是同步的。LinkedList,直接父类是AbstractSquentialList,数据结构是双向链表,它不是同步的,它同时实现了Deque(双向队列)和Queue(队 列)接口。同时它还提供了push和pop这两个堆栈操作的接口。Vector,直接父类是AbstractList,特性和ArrayList一样,只是它是线程同步的。Stack ,直接父类是Vector,实现堆栈这种数据结构。
(2)通过对象的equals方法。 解题思路:基础知识 考察点:考察对List的理解和运用以及equals的理解 分类:Java集合框架{校招,社招}
难度分级:P4
参考答案:
(1)使用循环结构 这种方法最灵活。唯一不足的地方可能就是代码较多 (2)使用Object类的clone()方法,
,,
这种方法最简单,得到原数组的一个副本。灵活形也最差。效率最差,尤其是在数组元素很大或者复制对象数组时。
(3) 使用Systems的arraycopy这种方法被告之速度最快,并且灵活性也较好,可以指定原数组名称、以及元素的开始位置、复 制的元素的个数,目标数组名称、目标数组的位置。
浅拷贝和深拷贝得理解:定义一个数组int[] a={3,1,4,2,5}; int[] b=a; 数组b只是对数组a的又一个引用,即浅拷贝。 如果改变数组b中元素的值,其实是改变了数组a的元素的值,要实现深度复制,可以用clone或者System.arrayCopy clone和System.arrayCopy都是对一维数组的深度复制;因为java中没有二维数组的概念,只有数组的数组。所以二维数组a中存储的实际上是两 个一维数组的引用。当调用clone函数时,是对这两个引用进行了复制。
解题思路:基础知识
考察点:数组拷贝,浅拷贝和深拷贝的区别
分类:{校招,社招}
难度分级:P4,P5
参考答案
S区即Survivor区,位于年轻代。年轻代分三个区。一个Eden 区,两个Survivor 区。大部分对象在Eden 区中生成。当Eden 区满时,还存活的对象将被复制到Survivor 区(两个中的一个),当这个Survivor 区满时,此区的存活对象将被复制到另外一个Survivor 区,当这个Survivor 去也满了的时候,从第一个Survivor 区复制过来的并且此时还存活的对象,将被复制年老区(Tenured)。需要注意,Survivor 的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden 复制过来对象,和从前一个Survivor 复制过来的对象,而复制到年老区的只有从第一个Survivor 去过来的对象。而且,Survivor 区总有一个是空的。
解题思路:基础知识 考察点:JVM 内存结构 分类:JVM GC {校招,社招} 难度分级:P4
参考答案:
http://outofmemory.cn/c/java-outOfMemoryError(OOM分类) http://www.51testing.com/html/92/77492-203728.html(jstat使用) http:// my.oschina.net/shaorongjie/blog/161385(MAT使用)
解题思路:基础知识 考察点:jstat mat工具 jvm 分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案:
1)对象优先在Eden分配;2)大对象直接进入老年代;3)长期存活的对象将进入老年代;4)动态对象年龄判定
参考文献:http://www.cnblogs.com/liangzh/archive/2012/07/03/2575252.html
解题思路:基础知识 考察点: jvm
分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案:
假设某条线程执行一个synchronized代码段,其间对某变量进行操作,JVM会依次执行如下动作: (1) 获取同步对象monitor (lock)
(2) 从主存复制变量到当前工作内存 (read and load)
(2) 从主存复制变量到当前工作内存 (read and load) (3) 执行代码,改变共享变量值 (use and assign)
(4) 用工作内存数据刷新主存相关内容 (store and write) (5) 释放同步对象锁 (unlock)
解题思路:基础知识 考察点: jvm
分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案:
Xmx设置JVM 的最大可用内存,Xms 设置JVM实际使用内存,一般Xmx和Xms相同,这是因为当Xmx内存空间不够用时,将进行扩容导致Full GC。将Xmx和Xms设置成相同的值,避免因Xms偏小导致频繁重新分配内存,影响应用使用。
解题思路:基础知识 考察点: jvm
分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案:
1、jps -v列出所有的java进程 , top找出cpu占用过高的对应的java 进程pid
2、使用top -H -p PID 命令查看对应进程里的哪个线程占用CPU过高,取该线程pid
3、将线程的pid 转成16进制
4、jstack [进程pid]|grep -A 100 [线程pid的16进制] dump出jvm该线程的后100行,或者整个输出到文件 jstack -l pid > xxxfile 参考文献:Crm线上机器发布时load过高案例分析阶段总结以及监控工具介绍
解题思路:基础知识 考察点: jvm 分类:JVM GC {社招} 难度分级:P5
参考答案:
JmapDump的文件一般比MAT工具大。创建索引期间,MAT会删除部分垃圾收集算法遗留下的不可达的object,因为回收这些较小的object代价 较大,一般这些object占比不超过4%。另外不能正确的写JmapDump的文件。尤其在较老的jvm(1.4,1.5)并且使用jmap命令获取JmapDump 的文件的时候。
解题思路:基础知识 考察点: jvm 分类:JVM GC {社招} 难度分级:P5
参考答案:
加-F参数
解题思路:基础知识 考察点: jvm 分类:JVM GC {社招} 难度分级:P5
参考答案: JVM参数设置
解题思路:基础知识 考察点: jvm
分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案: 这个是比较开发性试题,偏社招,考察面试者对系统的掌控力,一般都会从垃圾回收的角度来解释,比如用jstat或者gc日志来看ygc的单次时间和 频繁程度,full gc的单次时间和频繁程度;ygc的经验时间100ms以下,3秒一次;full gc 1秒以下 1小时一次,每次回收的比率70%等等,也会用jstack和jmap看系统是否有太多的线程和不必要的内存等等。关于如何才能让配置最优,有一些理 论支撑,比如高吞吐和延迟低的垃圾收集器选择,比如高并发对象存活时间不长,可以适当加大yong区;但是有经验的面试者会调整一些参数测试 来印证自己的想法。
解题思路:基础知识 考察点: jvm
分类:JVM GC {校招,社招}
分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案: (1)引用计数算法
原理:给对象添加一个引用计数器,每当有一个地方引用它时,计数器加1;引用失效时,计数器减1;计数器为0说明可被回收。 缺点:很难解决对象相互循环引用的问题(对象相互循环引用,但其实他们都已经没有用了。
(2)可达性分析算法
原理:通过一些列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。在java语言中,可作为GC Roots的对象包括下面几种:虚拟机栈(栈帧中的本地变量表)中引用的对象、方法区类静态属性引用的对象、方法区中常量引用的对象、本地方法 栈中JNI引用的对象、
参考文献:http://blog.csdn.net/chaofanwei/article/details/19541421 解题思路:基础知识 考察点:JVM GC 分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案:复制 解题思路:基础知识
考察点:JVM GC 分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案:
一般情况下,新生代中的对象大多生命周期很短,也就是说当进行垃圾收集时,大部分对象都是垃圾,只有一小部分对象会存活下来,所以只要保 留一小部分内存保存存活下来的对象就行了。在新生代中一般将内存划分为三个部分:一个较大的Eden空间和两个较小的Survior空间(一样大小 ),每次使用Eden和一个Survior的内存,进行垃圾收集时将Eden和使用的Survior中的存活的对象复制到另一个Survior空间中,然后清除这两个 空间的内存,下次使用Eden和另一个Survior,HotSpot中默认将这三个空间的比例划分为8:1:1,这样被浪费掉的空间就只有总内存的1/10了。 参考文献:http://www.cnblogs.com/angeldevil/p/3803969.html
解题思路:基础知识 考察点:JVM GC 分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案:
CMS以获取最短回收停顿时间为目标的收集器,使用“标记-清除”算法,分为以下6个步骤
1.STW initial mark:第一次暂停,初始化标记,从root标记old space存活对象(the set of objects reachable from roots (application code))
2.Concurrent marking:运行时标记,从上一步得到的集合出发,遍历old space,标记存活对象 (all live objects that are transitively reachable from previous set)
3.Concurrent precleaning:并发的标记前一阶段被修改的对象(card table)
4.STW remark:第二次暂停,检查,标记,检查脏页的对象,标记前一阶段被修改的对象 (revisiting any objects that were modified during the concurrent marking phase)
5.Concurrent sweeping:运行过程中清理,扫描old space,释放不可到达对象占用的空间 6.Concurrent reset:此次CMS结束后,重设CMS状态等待下次CMS的触发 或者4个大步骤: 1,initial mark 2,concurrent mark 3,remark 4,concurrent sweep 解题思路:基础知识 考察点:JVM GC 分类:JVM GC {校招,社招} 难度分级:P4,P5
young gc :eden空间不足
full gc :显示调用System.GC、旧生代空间不足、Permanet Generation空间满、CMS GC时出现promotion failed和concurrent mode failure、 RMI等的定时触发、YGC时的悲观策略、dump live的内存信息时
参考文献:http://blog.csdn.net/vernonzheng/article/details/8460128
http://blog.sina.com.cn/s/blog_7581a4c301019hsc.html
解题思路:基础知识
解题思路:基础知识 考察点:JVM GC 分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案:
垃圾回收器种类:
Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS(ConCurrent Mark Sweep)、G1(Garbage First)
垃圾回收扫描算法:
(,,) ,,,,
回收算法:
标记清除
,,,, ,,,
,
将内存划分为大小相等的两个区域,每次只使用其中的一个区域,当这个区域的内存用完了,就将可触及的对象直接复制到新的区域并连续存放以 消除内存碎片,当可触及对象复制完后,清除旧内存区域,修改引用的值。这种算法明显缺点是浪费内存,故实际使用中常将新生代划分成8:1:1三
个区。 标记整理
,,, ,,
分代收集
,,
的缺点,将内存划分为不同的区域,更多地收集短生命周期所在的内存区域,当对象经历一定次数的垃圾收集存活时,提升它的存在的区域。一般 是划 分为新生代和老年代。新生代又划分为Eden区,From Survior区和To Survior区
,
参考文献:http://www.cnblogs.com/angeldevil/p/3803969.html 解题思路:基础知识 考察点:JVM GC 分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案:
cms回收器的标记过程:
1.STW initial mark:第一次暂停,初始化标记,从root标记old space存活对象(the set of objects reachable from roots (application code))
2.Concurrent marking:运行时标记,从上一步得到的集合出发,遍历old space,标记存活对象 (all live objects that are transitively reachable from previous set)
3.Concurrent precleaning:并发的标记前一阶段被修改的对象(card table)
4.STW remark:第二次暂停,检查,标记,检查脏页的对象,标记前一阶段被修改的对象 (revisiting any objects that were modified during the concurrent marking phase)
内存碎片问题:
CMS基于“标记-清除”算法,进行垃圾回收后会存在内存碎片,当申请大的连续内存时可能内存不足,此时需要进行一次Full GC,可以通过参数指定进行Full GC后或进行多少次Full GC后进行一次内存压缩来整理内存碎片。
解题思路:基础知识 考察点:JVM GC 分类:JVM GC {校招,社招} 难度分级:P4,P5
参考 jvm gc介绍和日志说明 19、画一下JVM内存结构图,各块分别有什么的作用?-- by 刘柳 参考答案:
各模块作用:
程序技术器:是一块很小的内存区域,主要作用是记录当前线程所执行的字节码的行号。 虚拟机栈:是线程私有的,存放当前线程中局部基本类型的变量、部分的返回结果以及Stack Frame,非基本类型的对象的引用。Sun
JDK的实现中JVM栈的空间是在物理内存上分配的,而不是从堆上分配。
JDK的实现中JVM栈的空间是在物理内存上分配的,而不是从堆上分配。
堆:存储对象实例和数组区域 方法区域:是全局共享的,存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中 的方法信息。
本地方法堆栈:支持native方法的执行,存储每个native方法调用的状态。 解题思路:基础知识
考察点:JVM
分类:JVM {校招,社招}
难度分级:P4,P5
参考答案:
JVM认为在老年代或者永久区发生的gc行为就是Full GC,在ParNew+CMS条件下,发生Full GC的原因通常为: a) 永久区达到一定比例。 b) 老年代达到一定比例。
c) 悲观策略。
d) System.gc(), jmap -dump:live, jmap -histo:live 等主动触发的。 解题思路: 考察点:GC收集器 Full GC
分类:JVM GC {校招,社招}
难度分级:P4,P5
通过java -XX:+PrintStringTableStatistics命令查看,Number of buckets显示的就是StringPool的默认大小,在jdk7 u40版本以前,它的默认大小是1009,之后便调整为60013。
解题思路:JVM基础知识 考察点:StringPool 分类:JVM GC {校招,社招} 难度分级:P4,P5
参考答案:
StringPool在jdk6中是在永久区,dump heap时,无法输出。在jdk7中,stringpool移到heap中,可以输出。 解题思路:JVM基础知识 考察点:StringPool 分类:JVM GC {校招,社招} 难度分级:P4,P5
1、Java线程有哪些状态?并画出状态转换图 2、举例Java线程安全的实现方法,原理、区别?
参考答案:
互斥同步:synchronized关键字 , Lock ReentrantLock,volatile 非阻塞同步:原子变量 atomicLong 原理:sun.misc.Unsafe类,CAS指令
解题思路:基础知识 考察点:java 线程 分类:java 线程 {校招,社招}
分类:java 线程 {校招,社招} 难度分级:P4,P5
参考答案:
线程的start()只能被调用一次,否则会报java.lang.IllegalThreadStateException Thread类的start()方法
public synchronized void start() { if (threadStatus != 0)
throw new IllegalThreadStateException(); ......
}
解题思路:基础知识 考察点:java 线程 分类:java 线程 {校招,社招} 难度分级:P4,P5
参考答案:
sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行;yield()只是使当前线程重新回到可执行状态,所以执行yi eld()的线程有可能在进入到可执行状态后马上又被执行。 sleep()可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;yield()只能使同优先级的线程有执行的机会 。
解题思路:基础知识 考察点:java 线程 分类:java 线程 {校招,社招} 难度分级:P4,P5
参考答案:
1) 在需要同步的方法的方法签名中加入synchronized关键字。 2)使用synchronized块对需要进行同步的代码段进行同步。 3)使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象。 4)锁的粒度:类级别和对象级别 5)读写锁,CountDownLatch等的使用
6) Lock与synchronized 的区别
http://houlinyan.iteye.com/blog/1112535
解题思路:基础知识 考察点:java 线程 分类:java 线程 {校招,社招} 难度分级:P4,P5
参考答案:
wait()和notify()的区别:
http://blog.csdn.net/oracle_microsoft/article/details/6863662
wait和sleep的区别:
(1)sleep是Thread类的方法,是线程用来 控制自身流程的,比如有一个要报时的线程,每一秒中打印出一个时间,那么我就需要在print方法前面加上一个sleep让自己每隔一秒执行一次。 就像个闹钟一样。 wait是Object类的方法,用来线程间的通信,这个方法会使当前拥有该对象锁的进程等待知道其他线程调用notify方法时再醒来,不过你也可以给 他指定一个时间,自动醒来。这个方法主要是用走不同线程之间的调度的。
(2)关于锁的释放 ,在这里假设大家已经知道了锁的概念及其意义。调用sleep方法不会释放锁(自己的感觉是sleep方法本来就是和锁没有关系的,因为他是一个线 程用于管理自己的方法,不涉及线程通信)
(3)使用区域
由于wait函数的特殊意义,所以他是应该放在同步语句块中的,这样才有意义 。
注意:两个方法都需要抛出异常
解题思路:基础知识
考察点:
考察点: 分类:{校招,社招} 难度分级:P4
参考答案:
任务性质不同的任务可以用不同规模的线程池分开处理。CPU密集型任务配置尽可能小的线程,如配置Ncpu+1个线程的线程池。IO密集型任务则 由于线程并不是一直在执行任务,则配置尽可能多的线程,如2*Ncpu。混合型的任务,如果可以拆分,则将其拆分成一个CPU密集型任务和一个I O密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大 ,则没必要进行分解。我们可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数。 参考资料:http://www.infoq.co m/cn/articles/java-threadPool
解题思路:基础知识 考察点: 分类:{校招,社招} 难度分级:P4,P5
参考答案: http://wowlinda80.iteye.com/blog/228600 解题思路:基础知识 考察点: 分类:{校招,社招} 难度分级:P4,P5
参考答案: corePoolSize(线程池的基本大小):核心线程数,核心线程会一直存活,即使没有任务需要处理。当线程数小于核心线程数时,即使现有的线程
空闲,线程池也会优先创建新线程来处理任务,而不是直接交给现有的线程处理。
空闲,线程池也会优先创建新线程来处理任务,而不是直接交给现有的线程处理。 maximumPoolSize(线程池最大大小):当线程数大于或等于核心线程,且任务队列已满时,线程池会创建新的线程,直到线程数量达到maxPo olSize。如果线程数已等于maxPoolSize,且任务队列已满,则已超出线程池的处理能力,线程池会拒绝处理任务而抛出异常。 queueCapacity(任务队列容量):从maxPoolSize的描述上可以看出,任务队列的容量会影响到线程的变化,因此任务队列的长度也需要恰当的设 置。
参数的设置参考http://blog.csdn.net/zhouhl_cn/article/details/7392607
解题思路:最好搞清楚线程池的主要处理流程。 考察点:线程池的理解与使用 分类:{校招,社招} 难度分级:P4,P5
参考答案: http://wowlinda80.iteye.com/blog/228600
解题思路:最好搞清楚线程池的主要处理流程。 考察点:线程池的理解与使用 分类:{校招,社招} 难度分级:P4,P5
参考答案: 一写多读的情况主要需要考虑读到最新的数据,所以加volatile关键字即可
多写多读的情况就需要考虑原子操作,可以利用CAS原理 解题思路:基础知识 考察点:多线程,异步
分类:{校招,社招}
难度分级:P4,P5
参考答案:
这几点阐述的不完全正确
多线程优势 1.发挥多核处理器的强大能力,如果没有多核处理器,用多线程也只是形式而已,提升处理速度,常见的是一个任务用多线程跑比单线程跑快 2.建模简单,可以把一系列的复杂交互,变成简单的同步编程模型;比如我们在写controller时不用在考虑线程创建、销毁、调度优先级等;如果用 单线程模型会变得非常复杂。
3.异步事件的简化处理,参见NIO的实现
多线程的风险
1.线程安全性
2.活跃性(死锁)问题
3.性能问题,频繁切换上下文,调度
3.性能问题,频繁切换上下文,调度 想要同时处理多件事:单线程处理不了的,必须使用多线程。(类似于分身术) 多个线程分解大任务:用单线程可以做,但是使用多线程可以更快。(类似于左右开弓) 可以引申到异步和多线程的区别上。
解题思路:基础知识
考察点:多线程,异步
分类:{校招,社招都可以用}
难度分级:P4,P5
参考答案:
,, ,,,, ,,,, ,,,, ,,, ,,, ,,
这个例子不错:
多线程就是通过线程调用线程实现的;打个比方来说就像“摆渡”,河的一岸有很多的人,他们想过河,过河的过程做什么就是他们自己的逻辑, 只要他符合我的要求我就送你过河(线程池的要求就是实现Runnable或继承Thread类),然后我开了几条船去送人,只要河的这一岸有满足的人 ,我就送你过河。这个例子中河一岸的人就是我们要执行的任务,是一个集合,船就是线程池中的线程,由我们自己控制,过河这个动作就是要执 行的逻辑,我们只负责把船调给你,怎么划桨怎么过河就是程序自己的逻辑了。
解题思路:基础知识 考察点:线程池 分类:{校招,社招都可以用} 难度分级:P4,P5
参考答案:
参考答案:
【java】【分享】java多线程
解题思路:基础知识 考察点:Java线程状态 分类:{校招,社招} 难度分级:P4
参考答案:
线程状态以及相互转换图已有答案。 blocked是内部对象锁阻塞,另外blocked激活需要线程调度器允许其持有对象,waiting是等待其他线程通知线程调度器一个条件; BLOCK产生的原因:I/O等待阻塞,suspend挂起等
WAITING产生原因:Thread.sleep,Object.wait等
解题思路:基础知识
考察点:Java线程状态
分类:{校招,社招}
难度分级:P4
参考答案:
参考:http://houlinyan.iteye.com/blog/1112535 解题思路:基础知识 考察点:线程同步方式
分类:{校招,社招}
难度分级:P4
参考答案: 参考http://www.cnblogs.com/cxd4321/archive/2012/05/28/2521542.html 解题思路:基础知识 考察点:死锁
分类:{校招,社招}
难度分级:P4
public class Memoizer implements Computable { private final ConcurrentMap> cache = new ConcurrentHashMap>(); private final Computable c; public Memoizer(Computable c) { this.c = c; } public V compute(final A arg) throws InterruptedException { while (true) {
} }}
Future f = cache.get(arg); if (f == null) {
Callable eval = new Callable() { public V call() throws InterruptedException {
return c.compute(arg); }
}; FutureTask ft = new FutureTask(eval); f = cache.putIfAbsent(arg, ft); if (f == null) { f = ft; ft.run(); }
} try {
return f.get(); } catch (CancellationException e) { cache.remove(arg, f); } catch (ExecutionException e) { throw launderThrowable(e.getCause()); }
标准答案:
答案是JVM不能自动关闭线程池,销毁线程。 可以参考海丰的CRM每天第一次发布导致cpu load过高报警的问题 解题思路:基础知识
考察点:线程池
考察点:线程池 分类:{校招,社招都可以用} 难度分级:P4,P5
参考答案: 线程池在执行execute方法的时候,会根据初始化参数的大小以及线程池已有的线程数,来创建核心线程或者把task塞入任务队列;其中创建的核 心线程创建后会启动,run方法内会执行一个runWork函数,此函数会不断地从任务队列中获取task执行。 解题思路:线程池的工作原理和工作流程。 考察点:线程池
分类:{校招,社招都可以用}
难度分级:P4,P5
2.4、框架组件
三、Android相关
四、IOS相关
五、算法题
1、最短摘要生成
https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/%E6%9C%80%E7%9F%AD%E6%91%98%E8%A6%81%E7%9A%84%E7%94%9F%E6%88%90.md
六、逻辑题
1、捡肥皂
from:INF校招面试题目征集 有N(N>2)个同学站成一直排,裁判员一声令下,所有同学同时随机向左转或者向右转(包括队头队尾的也是随机),如果有两个同学面对面,
那么就可以愉快地去捡肥皂了,请问剩下来的人数的期望值是多少?(建议考试的时候将捡肥皂改为找朋友)
1. 分析:如果N=2,捡肥皂成功的概率是1/2 * 1/2 = 1/4;如果N=K+1,总的捡肥皂成功的pair数 = 前K个人成功的pair数+第K个人捡肥皂成功的概率,而第K个人成功的概率是1/4。所以N个人中总共预期有(N-1)/4对,也就是成功的人数 是(N-1)/2,剩下的人数是(N+1)/2。
考查要点:(1)基本的分析能力;(2)对复杂问题先从简单入手的能力,希望候选人先列举N=2, N=3, N=4...等几个简单的例子,然后从中发现规律。
笔试原则:
不考太偏太难的题目,着重考察候选人的基本功。力求候选人可以写出bugfree的代码,充分考虑各种边界条件及异常处理。
部分题目的描述可能不是很精确,也期望候选人可以提出问题,及时与面试官沟通。
注意:面试官需要根据候选人的背景,选用不同的题目。
简单难度:
1. 遍历1-100,被3整除的输出a, 被5整除的输出b,被15整除的输出c。
点评: 刚哥御用笔试题,考察点主要在于被15整除的数也可以被3和5整除,写代码的时候注意绕过这个逻辑即可,据说有50%的人写不出来,o(╯□╰)o。
2. 输入一个字符串,全是大写字母范围从'A'-'Z'(A,B,C,D,AA,AB,AC),输出相应的int值. (A=1,B=2,Z=26,AA=27...)
点评: 就是考察了一下 sum = sum * 26 + curr;
3. 求两个数的最大公约数
点评: 如果候选人知道辗转相除法,应该还是比较简单的。否则可能就写不出来了,面试官还是根据候选人的实际情况,看看要不要考察这道题目。
4. 判断一个字符串是不是回文, given "abcba" return true, given "abcab" return false;
点评: 超级简单有木有,最多5分钟,不能再多了。
5. 输入两个字符串表示version,"1.1.2", "1.1.1", 判断两个version那个是最新的。(简化一下,假定输入都是合法的)
"1.1.1" < "1.1.2"。 "2" > "1.1"
点评: 也没啥,就是考察写代码的基本功,拆分字符串,compare,循环等。
6. 有两个已经排好序的数组(升序),现在把这两个数组合成一个按升序排列的数组。
given array1=[1,3,5,7,9], given array2=[2,4,6,8,10], return newarray[1,2,3,4,5,6,7,8,9,10]
点评: 数组基本操作
7. 单词计数,输入一个字符串数组,统计每个单词出现的次数。
given ["boy","girl","boy"], return boy:2, girl:1
点评: 数据结构考察,用个map保存一下key,value即可,还是很简单的。
8. 给定两个区间,判断这两个区间是否重合,given [1,3],[5,6] return 不重合(false), given[1,3],[2,5] return 重合(true)
点评: 考察一下逻辑思维能力,没啥特别的,也就一行代码的事情。
9. 翻转链表
点评: 老题目,不过如果没准备的话,翻起来也没那么容易
10. 一个排好序的数组(升序),给一个数字,判断数组中是否有两个数加起来=给定的数字
array=[1,2,3,4,5], given target=8, return true(3+5==8), given 10, return false;
点评: 要求o(n)复杂度,两个指针,遍历一遍就行了。
中等难度:
1. 有一个排好序的数组(升序),给定一个数字,找出这个数字在这个数组中第一次出现的index,如果不在数组中则返回-1.
比如array=[1,2,2,3,4,5], target=2, return 1(第一次出现2的数组下标是1)
点评: 算法复杂度要求log(n),即要求候选人用二分查找来做,与经典的二分查找不一样,要求是要返回第一次出现该数字的index,只会'背'二分查找的同学是很难写出来的
2. 把字符串转成int,即输入"123",输出123。(不允许用库函数,绝对不允许)
点评: 很难的一道题目。各种边界考察,诸如正负号、非法字符、int越界。候选人考虑到的边界情况越多越好,不期望完全bugfree。
3. 给一个字符串,都是小写字母范围从'a'-'z', 其中有些字符出现了不止一次,删掉那些出现多次的字符,确保每个字符只出现一次。字符顺序不做要求。
比如 "bcabc", 返回"bca",或者"cab" 都是OK的。
点评: 就是考察一下字符串的基本操作,对数据结构的理解。
4. 求pi,没错就是求pi(圆周率)。
点评: 如果候选人有机器学习相关背景,并且对于蒙特卡罗方法比较熟悉的话,应该可以写出来。
5. 对一个整数开根号(不许用库函数)
点评: 方法应该有很多。这道题目还是为某些有机器学习背景的同学准备的。我本人是比较倾向于候选人用牛顿迭代法来做,
如果接触过一些机器学习或者上过类似计算方法这样的课程,应该是第一时间反应用牛顿迭代法。
6. 给4个数字,判断能不能用+-*/算出24点。比如 5,5,5,1。可以算出24点,返回true。 (5-1/5)*5 = 24;
点评:部分有竞赛背景的同学不妨拿这道题目难为一下,只用返回true or false就可以,不需要给出具体表达式。
对于有ACM背景的同学来说30分钟应该是可以写出来的,其他正常人类就不要用这道题目为难人家了。
7. 判断一个字符串是不是合法的ip(不许用正则)
点评: 考察字符串基本操作,各种边界条件。要想写个bugfree的没有那么简单。
8. 翻转一个int,即输入12345,输出54321. 输入-123,输出-321
点评: 候选人至少要考虑两个场景,负数和越界。其他的就是一些基本功的考察。写好也不容易。
9. 10进制数转成16进制(不许用库函数,不许用), given 100, return 64, given 250, return FA
点评: 就是各种基本功了,也没啥,力求代码写得好看点。
10. 有两个n维向量(n 很大),并且两个向量中有大量的0,求这两个向量的点积。
点积的定义: 给定两个向量,向量a[1,2,,,,n],向量b[1,2,,,,n],(两个向量的维度一定是一样的),点积= a1*b1 + a2*b2 + ....+ an*bn;
点评: 一个小算法,因为向量中有大量的0,所以可以用一些小技巧提高一下算点积的速度,仅此而已。
package sp.test;
import java.util.*;
/**
* Created by shipeng on 2017/8/9.
*/
public class EntryExam {
/**
* 1. 遍历1-100,被3整除的输出a, 被5整除的输出b,被15整除的输出c。
* 点评: 刚哥御用笔试题,考察点主要在于被15整除的数也可以被3和5整除,写代码的时候注意绕过这个逻辑即可,据说有50%的人写不出来,o(╯□╰)o。
*/
public static void easy1() {
for (int i = 1; i <= 100; i++) {
if (i % 15 == 0) {
System.out.println("c" + " " + i);
} else if (i % 3 == 0) {
System.out.println("a" + " " + i);
} else if (i % 5 == 0) {
System.out.println("b" + " " + i);
}
}
}
/**
* 2. 输入一个字符串,全是大写字母范围从'A'-'Z'(A,B,C,D,AA,AB,AC),输出相应的int值. (A=1,B=2,Z=26,AA=27...)
* 点评: 就是考察了一下 sum = sum * 26 + curr;
*/
public static int easy2(String input) {
if (input == null || input.length() < 1) {
return 0;
}
int sum = 0;
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c < 'A' || c > 'Z') {
return 0;
}
sum = sum * 26 + (c - 'A') + 1;
}
return sum;
}
/**
* 3. 求两个数的最大公约数
* 点评: 如果候选人知道辗转相除法,应该还是比较简单的。否则可能就写不出来了,面试官还是根据候选人的实际情况,看看要不要考察这道题目。
*/
public static int easy3(int a, int b) {
if (a < 1 || b < 1) {
return 1;
}
return gcdHelper(Math.max(a, b), Math.min(a, b));
}
private static int gcdHelper(int a, int b) {
if (a % b == 0) {
return b;
}
int c = a - b;
return gcdHelper(Math.max(b, c), Math.min(b, c));
}
/**
* 4. 判断一个字符串是不是回文, given "abcba" return true, given "abcab" return false;
* 点评: 超级简单有木有,最多5分钟,不能再多了。
*/
public static boolean easy4(String input) {
if (input == null || input.length() <= 1) {
return true;
}
for (int i = 0; i < input.length() / 2; i++) {
if (input.charAt(i) != input.charAt(input.length() - i - 1)) {
return false;
}
}
return true;
}
/**
* 5. 输入两个字符串表示version,"1.1.2", "1.1.1", 判断两个version那个是最新的。(简化一下,假定输入都是合法的)
* "1.1.1" < "1.1.2"。 "2" > "1.1"
* 点评: 也没啥,就是考察写代码的基本功,拆分字符串,compare,循环等。
*/
public static int easy5(String ver1, String ver2) {
if (ver1 == ver2) {
return 0;
}
if (ver1 == null) {
return -1;
}
if (ver2 == null) {
return 1;
}
String[] array1 = ver1.split("\\.");
String[] array2 = ver2.split("\\.");
int len1 = array1.length;
int len2 = array2.length;
for (int i = 0; i < Math.min(len1, len2); i++) {
int num1 = Integer.valueOf(array1[i]);
int num2 = Integer.valueOf(array2[i]);
if (num1 < num2) {
return -1;
} else if (num1 > num2) {
return 1;
}
}
return len1 > len2 ? 1 : -1;
}
/**
* 6. 有两个已经排好序的数组(升序),现在把这两个数组合成一个按升序排列的数组。
* given array1=[1,3,5,7,9], given array2=[2,4,6,8,10], return newarray[1,2,3,4,5,6,7,8,9,10]
* 点评: 数组基本操作
*
* @param array1
* @param array2
* @return
*/
public static int[] easy6(int[] array1, int[] array2) {
if (array1 == null || array1.length < 1) {
return array2;
}
if (array2 == null || array2.length < 1) {
return array1;
}
int len1 = array1.length;
int len2 = array2.length;
int[] merge = new int[len1 + len2];
int i = 0, j = 0, k = 0;
while (j < len1 && k < len2) {
if (array1[j] <= array2[k]) {
merge[i++] = array1[j++];
} else {
merge[i++] = array2[k++];
}
}
while (j < len1) {
merge[i++] = array1[j++];
}
while (k < len2) {
merge[i++] = array2[k++];
}
return merge;
}
/**
* 7. 单词计数,输入一个字符串数组,统计每个单词出现的次数。
* given ["boy","girl","boy"], return boy:2, girl:1
* 点评: 数据结构考察,用个map保存一下key,value即可,还是很简单的。
*/
public static void easy7(String[] words) {
if (words == null || words.length < 1) {
return;
}
Map
for (String word : words) {
if (wordCounts.containsKey(word)) {
wordCounts.put(word, wordCounts.get(word) + 1);
} else {
wordCounts.put(word, 1);
}
}
System.out.println("finish");
}
/**
* 8. 给定两个区间,判断这两个区间是否重合,given [1,3],[5,6] return 不重合(false), given[1,3],[2,5] return 重合(true)
* 点评: 考察一下逻辑思维能力,没啥特别的,也就一行代码的事情。
*/
public static boolean easy8(int[] interval1, int[] interval2) {
if (interval1 == null || interval2 == null) {
return false;
}
return !(interval1[0] > interval2[1] || interval1[1] < interval2[0]);
}
/**
* 9. 翻转链表
* 点评: 老题目,不过如果没准备的话,翻起来也没那么容易
*/
public static LinkedNode easy9(LinkedNode head) {
if (head == null || head.nextNode == null) {
return head;
}
LinkedNode curr = head;
LinkedNode pre = null;
LinkedNode next;
while (curr != null) {
next = curr.nextNode;
curr.nextNode = pre;
pre = curr;
curr = next;
}
return pre;
}
/**
* 10. 一个排好序的数组(升序),给一个数字,判断数组中是否有两个数加起来=给定的数字
* array=[1,2,3,4,5], given target=8, return true(3+5==8), given 10, return false;
* 点评: 要求o(n)复杂度,两个指针,遍历一遍就行了。
*/
public static boolean easy10(int[] array, int target) {
if (array == null || array.length < 2) {
return false;
}
int start = 0;
int end = array.length - 1;
while (start < end) {
if ((array[start] + array[end]) == target) {
return true;
} else if ((array[start] + array[end]) > target) {
end--;
} else {
start++;
}
}
return false;
}
/**
* 1. 有一个排好序的数组(升序),给定一个数字,找出这个数字在这个数组中第一次出现的index,如果不在数组中则返回-1.
* 比如array=[1,2,2,3,4,5], target=2, return 1(第一次出现2的数组下标是1)
* 点评: 算法复杂度要求log(n),即要求候选人用二分查找来做,与经典的二分查找不一样,要求是要返回第一次出现该数字的index,只会'背'二分查找的同学是很难写出来的
*
* @return
*/
public static int normal1(int[] array, int target) {
if (array == null || array.length < 1) {
return 0;
}
int start = 0;
int end = array.length - 1;
while (start <= end) {
int mid = (start + end) / 2;
if (array[mid] == target) {
int candidate = mid;
while (candidate >= 0 && array[candidate] == target) {
candidate--;
}
return candidate + 1;
} else if (array[mid] > target) {
end--;
} else {
start++;
}
}
return -1;
}
/**
* 2. 把字符串转成int,即输入"123",输出123。(不允许用库函数,绝对不允许)
* 点评: 很难的一道题目。各种边界考察,诸如正负号、非法字符、int越界。候选人考虑到的边界情况越多越好,不期望完全bugfree。
*/
public static int normal2(String str) {
boolean isNegative = false;
str = str.trim();
if (str.startsWith("-")) {
isNegative = true;
}
int sum = 0;
int multi = Integer.MAX_VALUE / 10;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (i == 0 && (c == '+' || c == '-')) {
continue;
}
if (c < '0' || c > '9') {
break;
}
if (sum > multi || ((sum == multi) && Integer.MAX_VALUE % 10 < (c - '0'))) {
return isNegative ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
sum = sum * 10 + (c - '0');
}
return isNegative ? -sum : sum;
}
/**
* 3. 给一个字符串,都是小写字母范围从'a'-'z', 其中有些字符出现了不止一次,删掉那些出现多次的字符,确保每个字符只出现一次。字符顺序不做要求。
* 比如 "bcabc", 返回"bca",或者"cab" 都是OK的。
* 点评: 就是考察一下字符串的基本操作,对数据结构的理解。
*/
public static String normal3(String str) {
if (str == null || str.length() < 1) {
return str;
}
int[] flag = new int[26];
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
flag[c - 'a']++;
}
char[] array = new char[26];
int j = 0;
for (int i = 0; i < flag.length; i++) {
if (flag[i] >= 1) {
array[j++] = (char) ('a' + i);
}
}
return new String(array, 0, j);
}
/**
* 4. 求pi,没错就是求pi(圆周率)。
* 点评: 如果候选人有机器学习相关背景,并且对于蒙特卡罗方法比较熟悉的话,应该可以写出来。
*/
public static float normal4() {
Random r = new Random();
int total = 10000000;
int sum = 0;
for (int i = 0; i < total; i++) {
//随机生成[0,1]之间的坐标点
double distance = Math.pow(r.nextFloat(), 2) + Math.pow(r.nextFloat(), 2);
if (distance <= 1) {
sum++;
}
}
return (float) sum * 4 / total;
}
/**
* 5. 对一个整数开根号(不许用库函数)
* 点评: 方法应该有很多。这道题目还是为某些有机器学习背景的同学准备的。我本人是比较倾向于候选人用牛顿迭代法来做,
* 如果接触过一些机器学习或者上过类似计算方法这样的课程,应该是第一时间反应用牛顿迭代法。
*/
public static float normal5(int m) {
// 牛顿迭代法,求解x^2-a=0
// y=f(x)'(x-x0) + f(x0)
// m=2x0(x1-x0)+x0^2 --> m=2x0*x1-x0^2 --> x1=(m+x0^2)/2x0
if (m <= 1) {
return m;
}
float err = 0.001f;
int maxIter = 100;
float currErr = m;
int i = 0;
float curr = 1;
float next = 0;
while (i < maxIter && currErr > err) {
next = (m + curr * curr) / 2 / curr;
currErr = Math.abs(next * next - m);
curr = next;
i++;
}
return next;
}
/**
* 6. 给4个数字,判断能不能用加减乘除算出24点。比如 5,5,5,1。可以算出24点,返回true。 (5-1/5)*5 = 24;
* 点评:部分有竞赛背景的同学不妨拿这道题目难为一下,只用返回true or false就可以,不需要给出具体表达式。
* 对于有ACM背景的同学来说30分钟应该是可以写出来的,其他正常人类就不要用这道题目为难人家了。
*/
public static boolean normal6(int[] array) {
if (array == null || array.length != 4) {
return false;
}
float[] newArray = new float[array.length];
for (int i = 0; i < newArray.length; i++) {
newArray[i] = array[i];
}
return helper(newArray);
}
private static boolean helper(float[] array) {
if (array.length == 2) {
if (array[0] + array[1] == 24) {
return true;
} else if (Math.abs(array[0] - array[1]) == 24) {
return true;
} else if (array[0] * array[1] == 24) {
return true;
} else {
if (array[0] != 0) {
if (array[1] / array[0] == 24) {
return true;
}
}
if (array[1] != 0) {
if (array[0] / array[1] == 24) {
return true;
}
}
}
return false;
}
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
float[] newArray = generateNewArray(array, i, j);
newArray[newArray.length - 1] = array[i] + array[j];
if (helper(newArray)) {
return true;
}
newArray[newArray.length - 1] = Math.abs(array[i] - array[j]);
if (helper(newArray)) {
return true;
}
newArray[newArray.length - 1] = array[i] * array[j];
if (helper(newArray)) {
return true;
}
if (array[i] != 0) {
newArray[newArray.length - 1] = array[j] / array[i];
if (helper(newArray)) {
return true;
}
}
if (array[j] != 0) {
newArray[newArray.length - 1] = array[i] / array[j];
if (helper(newArray)) {
return true;
}
}
}
}
return false;
}
private static float[] generateNewArray(float[] array, int i , int j) {
float[] res = new float[array.length - 1];
for (int k = 0, m = 0; k < array.length; k++) {
if (k != i && k != j) {
res[m++] = array[k];
}
}
return res;
}
/**
* 7. 判断一个字符串是不是合法的ip(不许用正则)
* 点评: 考察字符串基本操作,各种边界条件。要想写个bugfree的没有那么简单。
*/
public static boolean normal7(String str) {
if (null == str || str.length() < 7 || str.length() > 15) {
return false;
}
String[] parts = str.split("\\.");
if (parts.length != 4) {
return false;
}
try {
for (int i = 0; i < parts.length; i++) {
int num = Integer.parseInt(parts[i]);
if (num < 0 || num > 255) {
return false;
}
}
} catch (Exception e) {
return false;
}
return true;
}
/**
* 8. 翻转一个int,即输入12345,输出54321. 输入-123,输出-321
* 点评: 候选人至少要考虑两个场景,负数和越界。其他的就是一些基本功的考察。写好也不容易。
*/
public static int normal8(int a) {
int sign = a < 0 ? -1 : 1;
a = Math.abs(a);
int sum = 0;
int[] tmp = new int[10];
int max = 0;
while (a > 0) {
tmp[max++] = a % 10;
a = a / 10;
}
int multi = Integer.MAX_VALUE / 10;
for (int i = 0; i < max; i++) {
// 判断是否越界,如果越界就返回Integer.MAX_VALUE
if (sum > multi || ((sum == multi) && Integer.MAX_VALUE % 10 < tmp[i])) {
return Integer.MAX_VALUE * sign;
}
sum = sum * 10 + tmp[i];
}
if (sum < 0) {
return Integer.MAX_VALUE * sign;
}
return sum * sign;
}
/**
* 9. 10进制数转成16进制(不许用库函数,不许用), given 100, return 64, given 250, return FA
* 简化一下,只考虑正数,负数的十六进制表达有点怪怪的。
* 点评: 就是各种基本功了,也没啥,力求代码写得好看点。
*/
public static String normal9(int m) {
char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
m = Math.abs(m);
StringBuilder sb = new StringBuilder();
while (m > 0) {
sb.append(chars[m % 16]);
m = m / 16;
}
return sb.reverse().toString();
}
/**
* 10. 有两个n维向量(n 很大),并且两个向量中有大量的0,求这两个向量的点积。
* 点积的定义: 给定两个向量,向量a[1,2,,,,n],向量b[1,2,,,,n],(两个向量的维度一定是一样的),点积= a1*b1 + a2*b2 + ....+ an*bn;
* 点评: 一个小算法,因为向量中有大量的0,所以可以用一些小技巧提高一下算点积的速度,仅此而已。
*/
public static int normal10(int[] array1, int[] array2) {
if (array1 == null || array2 == null) {
return 0;
}
if (array1.length != array2.length) {
return 0;
}
Set
for (int i = 0; i < array1.length; i++) {
if (array1[i] != 0) {
nonZero.add(i);
}
}
int sum = 0;
for (int i = 0; i < array2.length; i++) {
if (array2[i] != 0 && nonZero.contains(i)) {
sum += array1[i] * array2[i];
}
}
return sum;
}
private static class LinkedNode {
public LinkedNode() {
}
public LinkedNode(int val) {
this.val = val;
}
public int val;
public LinkedNode preNode;
public LinkedNode nextNode;
}
public static void main(String[] args) {
EntryExam.easy1();
System.out.println(EntryExam.easy2("A"));
System.out.println(EntryExam.easy3(3, 5));
System.out.println(EntryExam.easy4("abcab"));
System.out.println(EntryExam.easy5("1.0.1", "1.0"));
EntryExam.easy6(new int[]{1, 3, 5, 7, 9}, new int[]{2, 4, 6, 8});
EntryExam.easy7(new String[]{"boy1", "boy2", "boy1", "boy3"});
System.out.println(EntryExam.easy8(new int[]{1, 3}, new int[]{4, 5}));
LinkedNode node1 = new LinkedNode(1);
LinkedNode node2 = new LinkedNode(2);
LinkedNode node3 = new LinkedNode(3);
node1.nextNode = node2;
node2.nextNode = node3;
EntryExam.easy9(node1);
System.out.println(EntryExam.easy10(new int[]{1, 3, 4}, 6));
System.out.println(EntryExam.normal1(new int[]{1, 2, 2, 3, 4}, 2));
System.out.println(EntryExam.normal2("2113"));
System.out.println(EntryExam.normal3("leetcode"));
System.out.println(EntryExam.normal4());
System.out.println(EntryExam.normal5(5));
System.out.println(EntryExam.normal6(new int[]{4, 10, 10, 4}));
System.out.println(EntryExam.normal7("127.0.0.1"));
System.out.println(EntryExam.normal8(1234567899));
System.out.println(EntryExam.normal9(-255));
System.out.println(EntryExam.normal10(new int[]{0, 3, 0, 0, 0}, new int[]{1, 2, 3, 4, 5}));
}
}
学生成绩表t1,表结构如下
学号 |
课程 |
成绩 |
---|---|---|
1 | 语文 | 90 |
... | ... | ... |
1、总共有多少学生 (难度:)
答案: select count(distinct 学号) from t1
2、得到平均成绩大于90分的学生 (难度:)
答案:select 学号 from t1 group by 学号 having avg(成绩)>90
考察重点: having关键词,而不是where
3、得到同时选修语文和数学的学生 (难度:)
答案:
两种方法:使用join 或者使用 in
select 学号 from
(select distinct 学号 from t1 where 课程 = ‘语文’ ) a
join
(select distinct 学号 from t1 where 课程 = ‘数学' ) b on a.学号 = b.学号
或者
select distinct 学号 from t1
where 课程 = ‘语文’ and 学号 in (select 学号 from t1 where 课程 = ‘数学' )
如果面试者回答 课程 in (‘语文’,'数学'),这个错误的。因为使用in表示选修了语文或数学,而要求是学了语文和数学。
4、选出每门课程的top3学生、成绩以及排名 (难度:)
select 课程,学号,成绩,row_number() over (partition by 课程 order by 成绩 desc) rn
where rn <3
重点:考察 row_number, partition by
数据结构 & 算法
网络
系统
语言