微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!
架构师眼中的高并发架构
摘要: 以架构师的眼光来讲述高并发架构前言高并发经常会发生在有大活跃用户量,用户高聚集的业务场景中,如:秒杀活动,定时领取红包等。为了让业务可以流畅的运行并且给用户一个好的交互体验,我们需要根据业务场景预估达到的并发量等因素,来设计适合自己业务场景的高并发处理方案。在电商相关产品开发的这些年,我有幸的遇到了并发下的各种坑,这一路摸爬滚打过来有着不少的血泪史,这里进行的总结,作为自己的归档记录,同时分享给大家。服务器架构业务从发展的初期到逐渐成熟,服务器架构也是从相对单一到集群,再到分布式服务。 一个可以支持高并发的服务少不了好的服务器架构,需要有均衡负载,数据库需要主从集群,nosql缓存需要主从集群,静态文件需要上传cdn,这些都是能让业务程序流畅运行的强大后盾。服务器这块多是需要运维人员来配合搭建,具体我就不多说了,点到为止。大致需要用到的服务器架构如下:服务器均衡负载(如:nginx,阿里云SLB)资源监控分布式数据库主从分离,集群DBA 表优化,索引优化,等分布式nosqlredis主从分离,集群mongodb主从分离,集群memcache主从分离,集群cdnhtmlcssjsimage并发测试高并发相关的业务,需要进行并发的测试,通过大量的数据分析评估出整个架构可以支撑的并发量。测试高并发可以使用第三方服务器或者自己测试服务器,利用测试工具进行并发请求测试,分析测试数据得到可以支撑并发数量的评估,这个可以作为一个预警参考,俗话说知己自彼百战不殆。第三方服务:阿里云性能测试并发测试工具:Apache JMeterVisual Studio性能负载测试Microsoft Web Application Stress Tool实战方案通用方案日用户流量大,但是比较分散,偶尔会有用户高聚的情况;场景: 用户签到,用户中心,用户订单,等服务器架构图: 说明:场景中的这些业务基本是用户进入APP后会操作到的,除了活动日(618,双11,等),这些业务的用户量都不会高聚集,同时这些业务相关的表都是大数据表,业务多是查询操作,所以我们需要减少用户直接命中DB的查询;优先查询缓存,如果缓存不存在,再进行DB查询,将查询结果缓存起来。更新用户相关缓存需要分布式存储,比如使用用户ID进行hash分组,把用户分布到不同的缓存中,这样一个缓存集合的总量不会很大,不会影响查询效率。方案如:用户签到获取积分计算出用户分布的key,redis hash中查找用户今日签到信息如果查询到签到信息,返回签到信息如果没有查询到,DB查询今日是否签到过,如果有签到过,就把签到信息同步redis缓存。如果DB中也没有查询到今日的签到记录,就进行签到逻辑,操作DB添加今日签到记录,添加签到积分(这整个DB操作是一个事务)缓存签到信息到redis,返回签到信息注意这里会有并发情况下的逻辑问题,如:一天签到多次,发放多次积分给用户。我的博文[大话程序猿眼里的高并发]有相关的处理方案。用户订单这里我们只缓存用户第一页的订单信息,一页40条数据,用户一般也只会看第一页的订单数据用户访问订单列表,如果是第一页读缓存,如果不是读DB计算出用户分布的key,redis hash中查找用户订单信息如果查询到用户订单信息,返回订单信息如果不存在就进行DB查询第一页的订单数据,然后缓存redis,返回订单信息用户中心计算出用户分布的key,redis hash中查找用户订单信息如果查询到用户信息,返回用户信息如果不存在进行用户DB查询,然后缓存redis,返回用户信息其他业务上面例子多是针对用户存储缓存,如果是公用的缓存数据需要注意一些问题,如下注意公用的缓存数据需要考虑并发下的可能会导致大量命中DB查询,可以使用管理后台更新缓存,或者DB查询的锁住操作。我的博文[大话Redis进阶]对更新缓存问题和推荐方案的分享。以上例子是一个相对简单的高并发架构,并发量不是很高的情况可以很好的支撑,但是随着业务的壮大,用户并发量增加,我们的架构也会进行不断的优化和演变,比如对业务进行服务化,每个服务有自己的并发架构,自己的均衡服务器,分布式数据库,nosql主从集群,如:用户服务、订单服务;消息队列秒杀、秒抢等活动业务,用户在瞬间涌入产生高并发请求场景:定时领取红包,等服务器架构图:说明:场景中的定时领取是一个高并发的业务,像秒杀活动用户会在到点的时间涌入,DB瞬间就接受到一记暴击,hold不住就会宕机,然后影响整个业务;像这种不是只有查询的操作并且会有高并发的插入或者更新数据的业务,前面提到的通用方案就无法支撑,并发的时候都是直接命中DB;设计这块业务的时候就会使用消息队列的,可以将参与用户的信息添加到消息队列中,然后再写个多线程程序去消耗队列,给队列中的用户发放红包;方案如:定时领取红包一般习惯使用 redis的 list当用户参与活动,将用户参与信息push到队列中然后写个多线程程序去pop数据,进行发放红包的业务这样可以支持高并发下的用户可以正常的参与活动,并且避免数据库服务器宕机的危险附加: 通过消息队列可以做很多的服务。 如:定时短信发送服务,使用sset(sorted set),发送时间戳作为排序依据,短信数据队列根据时间升序,然后写个程序定时循环去读取sset队列中的第一条,当前时间是否超过发送时间,如果超过就进行短信发送。一级缓存高并发请求连接缓存服务器超出服务器能够接收的请求连接量,部分用户出现建立连接超时无法读取到数据的问题;因此需要有个方案当高并发时候时候可以减少命中缓存服务器;这时候就出现了一级缓存的方案,一级缓存就是使用站点服务器缓存去存储数据,注意只存储部分请求量大的数据,并且缓存的数据量要控制,不能过分的使用站点服务器的内存而影响了站点应用程序的正常运行,一级缓存需要设置秒单位的过期时间,具体时间根据业务场景设定,目的是当有高并发请求的时候可以让数据的获取命中到一级缓存,而不用连接缓存nosql数据服务器,减少nosql数据服务器的压力比如APP首屏商品数据接口,这些数据是公共的不会针对用户自定义,而且这些数据不会频繁的更新,像这种接口的请求量比较大就可以加入一级缓存;服务器架构图:合理的规范和使用nosql缓存数据库,根据业务拆分缓存数据库的集群,这样基本可以很好支持业务,一级缓存毕竟是使用站点服务器缓存所以还是要善用。静态化数据高并发请求数据不变化的情况下如果可以不请求自己的服务器获取数据那就可以减少服务器的资源压力。对于更新频繁度不高,并且数据允许短时间内的延迟,可以通过数据静态化成JSON,XML,HTML等数据文件上传CDN,在拉取数据的时候优先到CDN拉取,如果没有获取到数据再从缓存,数据库中获取,当管理人员操作后台编辑数据再重新生成静态文件上传同步到CDN,这样在高并发的时候可以使数据的获取命中在CDN服务器上。CDN节点同步有一定的延迟性,所以找一个靠谱的CDN服务器商也很重要其他方案对于更新频繁度不高的数据,APP,PC浏览器,可以缓存数据到本地,然后每次请求接口的时候上传当前缓存数据的版本号,服务端接收到版本号判断版本号与最新数据版本号是否一致,如果不一样就进行最新数据的查询并返回最新数据和最新版本号,如果一样就返回状态码告知数据已经是最新。减少服务器压力:资源、带宽分层,分割,分布式大型网站要很好支撑高并发,这是需要长期的规划设计 在初期就需要把系统进行分层,在发展过程中把核心业务进行拆分成模块单元,根据需求进行分布式部署,可以进行独立团队维护开发。分层将系统在横向维度上切分成几个部分,每个部门负责一部分相对简单并比较单一的职责,然后通过上层对下层的依赖和调度组成一个完整的系统比如把电商系统分成:应用层,服务层,数据层。(具体分多少个层次根据自己的业务场景)应用层:网站首页,用户中心,商品中心,购物车,红包业务,活动中心等,负责具体业务和视图展示服务层:订单服务,用户管理服务,红包服务,商品服务等,为应用层提供服务支持数据层:关系数据库,nosql数据库 等,提供数据存储查询服务分层架构是逻辑上的,在物理部署上可以部署在同一台物理机器上,但是随着网站业务的发展,必然需要对已经分层的模块分离部署,分别部署在不同的服务器上,使网站可以支撑更多用户访问分割在纵向方面对业务进行切分,将一块相对复杂的业务分割成不同的模块单元包装成高内聚低耦合的模块不仅有助于软件的开发维护,也便于不同模块的分布式部署,提高网站的并发处理能力和功能扩展比如用户中心可以分割成:账户信息模块,订单模块,充值模块,提现模块,优惠券模块等分布式分布式应用和服务,将分层或者分割后的业务分布式部署,独立的应用服务器,数据库,缓存服务器当业务达到一定用户量的时候,再进行服务器均衡负载,数据库,缓存主从集群分布式静态资源,比如:静态资源上传cdn分布式计算,比如:使用hadoop进行大数据的分布式计算分布式数据和存储,比如:各分布节点根据哈希算法或其他算法分散存储数据网站分层-图1来自网络集群对于用户访问集中的业务独立部署服务器,应用服务器,数据库,nosql数据库。 核心业务基本上需要搭建集群,即多台服务器部署相同的应用构成一个集群,通过负载均衡设备共同对外提供服务, 服务器集群能够为相同的服务提供更多的并发支持,因此当有更多的用户访问时,只需要向集群中加入新的机器即可, 另外可以实现当其中的某台服务器发生故障时,可以通过负载均衡的失效转移机制将请求转移至集群中其他的服务器上,因此可以提高系统的可用性应用服务器集群nginx 反向代理slb… …(关系/nosql)数据库集群主从分离,从库集群通过反向代理均衡负载-图2来自网络异步在高并发业务中如果涉及到数据库操作,主要压力都是在数据库服务器上面,虽然使用主从分离,但是数据库操作都是在主库上操作,单台数据库服务器连接池允许的最大连接数量是有限的 当连接数量达到最大值的时候,其他需要连接数据操作的请求就需要等待有空闲的连接,这样高并发的时候很多请求就会出现connection time out 的情况 那么像这种高并发业务我们要如何设计开发方案可以降低数据库服务器的压力呢?如:自动弹窗签到,双11跨0点的时候并发请求签到接口双11抢红包活动双11订单入库等设计考虑:逆向思维,压力在数据库,那业务接口就不进行数据库操作不就没压力了数据持久化是否允许延迟?如何让业务接口不直接操作DB,又可以让数据持久化?方案设计:像这种涉及数据库操作的高并发的业务,就要考虑使用异步了客户端发起接口请求,服务端快速响应,客户端展示结果给用户,数据库操作通过异步同步如何实现异步同步?使用消息队列,将入库的内容enqueue到消息队列中,业务接口快速响应给用户结果(可以温馨提示高峰期延迟到账)然后再写个独立程序从消息队列dequeue数据出来进行入库操作,入库成功后刷新用户相关缓存,如果入库失败记录日志,方便反馈查询和重新持久化这样一来数据库操作就只有一个程序(多线程)来完成,不会给数据带来压力补充:消息队列除了可以用在高并发业务,其他只要有相同需求的业务也是可以使用,如:短信发送中间件等高并发下异步持久化数据可能会影响用户的体验,可以通过可配置的方式,或者自动化监控资源消耗来切换时时或者使用异步,这样在正常流量的情况下可以使用时时操作数据库来提高用户体验异步同时也可以指编程上的异步函数,异步线程,在有的时候可以使用异步操作,把不需要等待结果的操作放到异步中,然后继续后面的操作,节省了等待的这部分操作的时间缓存高并发业务接口多数都是进行业务数据的查询,如:商品列表,商品信息,用户信息,红包信息等,这些数据都是不会经常变化,并且持久化在数据库中高并发的情况下直接连接从库做查询操作,多台从库服务器也抗不住这么大量的连接请求数(前面说过,单台数据库服务器允许的最大连接数量是有限的)那么我们在这种高并发的业务接口要如何设计呢?设计考虑:还是逆向思维,压力在数据库,那么我们就不进行数据库查询数据不经常变化,我们为啥要一直查询DB?数据不变化客户端为啥要向服务器请求返回一样的数据?方案设计:数据不经常变化,我们可以把数据进行缓存,缓存的方式有很多种,一般的:应用服务器直接Cache内存,主流的:存储在memcache、redis内存数据库Cache是直接存储在应用服务器中,读取速度快,内存数
Java中IO流,输入输出流概述与总结
总结的很粗糙,以后时间富裕了好好修改一下。1:Java语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在java.io包中。其中,所有输入流类都是抽象类InputStream(字节输入流),或者抽象类Reader(字符输入流)的子类;而所有输出流都是抽象类OutputStream(字节输出流)或者Writer(字符输出流)的子类。【首先需要明白的是:流是干什么的???(为了永久性的保存数据)  根据数据流向的不同分为输入流和输出流;  根据处理数据类型的不同分为字符流和字节流;】【然后需要明白的是输入模式和输出模式是谁流向谁:InputStream(字节输入流)和Reader(字符输入流)通俗的理解都是读(read)的。OutputStream(字节输出流)和Writer(字符输出流)通俗的理解都是写(writer)的。】最后下面搞清楚各种流的类型的该怎么用,谁包含谁,理清思路。2:InputStream类是字节输入流的抽象类,是所有字节输入流的父类,InputStream类具有层次结构如下图所示;3:java中的字符是Unicode编码的,是双字节的。InputStream是用来处理字节的,在处理字符文本时很不方便。Java为字符文本的输入提供了专门的一套类Reader。Reader类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。4:输出流OutputStream类是字节输入流的抽象类,此抽象类表示输出字节流的所有类的超类。5:Writer类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。6:File类是IO包中唯一代表磁盘文件本身的对象。通过File来创建,删除,重命名文件。File类对象的主要作用就是用来获取文本本身的一些信息。如文本的所在的目录,文件的长度,读写权限等等。(有的需要记忆,比如isFile(),isDirectory(),exits();有的了解即可。使用的时候查看API)详细如下:File类(File类的概述和构造方法)A:File类的概述File更应该叫做一个路径文件路径或者文件夹路径路径分为绝对路径和相对路径绝对路径是一个固定的路径,从盘符开始相对路径相对于某个位置,在eclipse下是指当前项目下,在dos下查看API指的是当前路径文件和目录路径名的抽象表示形式B:构造方法File(String pathname):根据一个路径得到File对象File(String parent, String child):根据一个目录和一个子文件/目录得到File对象File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象 File类(File类的创建功能)A:创建功能public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来(使用createNewFile()文件创建的时候不加.txt或者其他后缀也是文件,不是文件夹;使用mkdir()创建文件夹的时候,如果起的名字是比如aaa.txt也是文件夹不是文件;)注意事项:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。 File类(File类的重命名和删除功能)A:重命名和删除功能public boolean renameTo(File dest):把文件重命名为指定的文件路径public boolean delete():删除文件或者文件夹B:重命名注意事项如果路径名相同,就是改名。如果路径名不同,就是改名并剪切。C:删除注意事项:Java中的删除不走回收站。要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹 File类(File类的判断功能)A:判断功能public boolean isDirectory():判断是否是目录public boolean isFile():判断是否是文件public boolean exists():判断是否存在public boolean canRead():判断是否可读public boolean canWrite():判断是否可写public boolean isHidden():判断是否隐藏 File类(File类的获取功能)A:获取功能public String getAbsolutePath():获取绝对路径public String getPath():获取路径public String getName():获取名称public long length():获取长度。字节数public long lastModified():获取最后一次的修改时间,毫秒值public String[] list():获取指定目录下的所有文件或者文件夹的名称数组public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组 File类(文件名称过滤器的概述及使用)A:文件名称过滤器的概述public String[] list(FilenameFilter filter)public File[] listFiles(FileFilter filter) 1 package com.ningmeng;23 import java.io.File;45 public class Test {67 public static void main(String[] args) throws Exception{8 // TODO Auto-generated method stub9 File file=new File("aa.txt");//文件默认就创建在你创建的项目下面,刷新即可看到10 System.out.println(file.exists());//判断文件是否存在11 file.createNewFile();//创建文件,不是文件夹12 System.out.println(file.exists());//再次判断是否存在13 System.out.println(file.getName());//获取文件的名字14 System.out.println(file.getAbsolutePath());//获取文件的绝对路径15 System.out.println(file.getPath());//获取文件的相对路径16 System.out.println(file.getParent());//获取文件的父路径17 System.out.println(file.canRead());//文件是否可读18 System.out.println(file.canWrite());//文件是否可写19 System.out.println(file.length());//文件的长度20 System.out.println(file.lastModified());//文件最后一次修改的时间21 System.out.println(file.isDirectory());//判断文件是否是一个目录22 System.out.println(file.isHidden());//文件是否隐藏23 System.out.println(file.isFile());//判断文件是否存在24 }2526 }public String[] list():获取指定目录下的所有文件或者文件夹的名称数组public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组list()获取某个目录下所有的文件或者文件夹:1 package com.ningmeng;23 import java.io.File;45 public class FileTest {67 public static void main(String[] args){8 File file=new File("D:/");//指定文件目录9 String[] str=file.list();//获取指定目录下的所有文件或者文件夹的名称数组10 for(String s : str){//加强for循环遍历输出11 System.out.println(s);12 }1314 }15 }1 package com.ningmeng;23 import java.io.File;45 public class FileTest {67 public static void main(String[] args){8 File file=new File("D:/");//指定文件路径9 File[] f=file.listFiles();//获取指定目录下的所有文件或者文件夹的File数组10 for(File fi : f){//加强for循环遍历输出11 System.out.println(fi);12 }1314 }15 }案例演示:获取某种格式的文件比如获取某种后缀的图片,并输出文件名:1 package com.ningmeng;23 import java.io.File;45 public class FileTest {67 public static void main(String[] args){8 File file=new File("C:\Users\biehongli\Pictures\xuniji");9 String[] str=file.list();1011 for(String s : str){12 if(s.endsWith(".jpg") || s.endsWith(".png")){//如果后缀是这种格式的就输出13 System.out.println(s);14 }15 }161718 }19 }下面演示获取文件夹下面子目录里面的文件获取(并没有完全获取子目录的子目录等等,仅仅获取了子一级目录):1 package com.ningmeng;23 import java.io.File;45 public class FileTest {67 public static void main(String[] args){8 File file=new File("C:\Users\biehongli\Pictures\Camera Roll");910 File[] f=file.listFiles();1112 for(File fi : f){13 if(fi.isDirectory()){//判断如果是一个目录14 String[] s=fi.list();15 for(String str : s){16 if(str.endsWith(".jpg")){17
假如时光倒流,我会这么学习Java
回头看看, 我进入Java 领域已经快15个年头了, 虽然学的也一般, 但是分享下我的心得,估计也能帮大家少走点弯路。[入门]我在2001年之前是C/C++阵营, 有C和面向对象的基础, 后来转到Java ,发现没有指针的Java真是好简单, 另外Java 的类库好用的让人哭啊。后来我就看《Thinking in Java》 ,《 Java 核心技术 》, 感觉也不吃力。如果我之前没学过别的语言,或者半路出家转到计算机行业, 我不会先看上面那两本, 相反我会选《Head First Java》, 这本书非常适合零基础的小白, 读起来轻松搞笑, 不信你看看第一页但是光看书也挺无趣的,不妨和视频结合着看, 我觉得传智播客的Java基础视频很不错 (唉, 给传智打了个广告), 网上一搜就有,真搜不到就来我的公众号获取吧(Java团长)注意:视频的好处就是能看到敲代码的过程, 代码是活的, 这点很爽。 如果视频只是按PPT讲编程, 果断扔掉。书也有书的好处,能写成书的, 肯定是作者经过系统化思考,梳理才能形成的东西, 所以系统性比较强。书还有其他优点, 例如可以随便的翻, 找到重点反复的看。所以混合着看经典书+优秀的视频 应该是最好的入门。Java 入门, 我不会去上培训班,白白浪费钱 ,自学就够了。自学过程中如果有实战经验丰富的高人指导一下, 给我绘出路线图, 指出攀登的方向,哪些地方有陷阱, 哪些地方不应该浪费时间, 我的自学就可以减少摸索,少走弯路,很不幸, 我当年没有遇到, 如果时光倒流, 我会想办法找一个来指导我。[实践]软件行业的一大特点就是光看不做永远都学不会,编码不到10万行都不好意思出去打招呼。所以实践,实践,实践!在校期间,我还是会尽可能的去找项目做(参见我的另一篇文章《从现在开始丰富你的简历》, 回复“简历”查看) , 实在没找到,也可以先把基础打好我上大学的时候用的是严蔚敏的《数据结构》, 当时我也把习题都做了一遍,考高级程序员的时候, 成绩非常好。后来我知道了一本更好的算法入门书《算法》, 如果时光能够重来, 我还是会这本书上提到的所有数据结构和算法用Java 都实现一遍, 课后作业也争取都做一遍。这是个非常重要的训练,因为我知道, 真的做了, 就会发现工作以后只要不是设计算法, 基本的数据结构没有能难住我的。【Java SE】对于Java集合框架, 不但要学会用, 我还会尝试着实现一遍,List, ArrayList, Set ,HashSet, Map ,HashSet 等等, 要是不知道怎么写, 看看JDK的源码就可以了, 那里有最好的老师。实现一遍能更好的明白面向对象的设计, 接口,抽象类, 具体类的关系, 怎么分离职责,会学习到设计模式中的模板方法, Iterator 等 。值得一提的是Iterator, 很有趣, 我还清楚的记得那一年自己实现集合框架中 Iterator 的时候的激动心情啊 :-)在实现Java 集合框架的时候, 可以顺便把泛型也学了, 不学不行,要不然实现不了啊。Java 世界里,万事万物都是对象, 大家都知道封装,继承,多态, 但是仅仅了解这些只是入了门, 不可能做出真正的面向对象的程序。有一本经典的书《敏捷软件开发, 原则,模式,实践》,里边详细的讲解了一个薪水支付案例,是迄今为止最好的面向对象设计的例子我会用Java 把它实现一遍, 真正的体会一下OOD, 了解怎么才能把合适的责任分给合适的类, 什么叫面向接口而不是面向实现编程, 什么是优先使用组合而不是继承。对于Java线程, 重点还是理解概念, 因为我知道在以后的工作中(除非从事系统级编程) ,自己写线程/线程池的机会是非常罕见的,都被类库,框架给封装好了。所以重点是理解,看书的话就当然是《Java并发编程实战》 ,一大群大牛写的啊。对于Java IO, 我觉得架构设计的很优雅,典型的学院派, 可就是不太实用, 打开读取一个文件都得用装饰者模式包装来包装去, 太累了。项目实战中呢,也就是读取个property 文件, xml 文件。 我还是重点去理解概念和设计吧。不过自己写个简单的xml 解析器倒是不错。至于 AWT, Swing , 简单看看就行了, 我不会去深入研究, Java 是典型的服务器端的语言, 开发客户端程序的极少, 你想想, 你用Swing/AWT搞个桌面程序出来, 还得让客户装个JRE才能运行, 是不是有点过分 ? 据我所知,也即是银行的一些应用在用Swing ,AWT了。 有人可能说 Applet, 它曾经流行过, 现在早都没人用了。所以我不会在Swing和AWT上浪费时间。Java Reflection 看起来没有集合框架,线程,OO等那么耀眼, 但它可是很多框架(SSH) 的基础啊(回复“反射”查看相关文章), 先把基础学会,后面的Java EE得用到它。想真正的学好Java ,不了解Java 虚拟机怎么可能? 《深入理解Java 虚拟机》一定得看,看完的目标就是写个简单的Java 反编译器。【做个有素养的Java码农】我记得08的时候, 我的IBM经理说设计模式是必备技能, 不懂设计模式的我们不能要了。所以设计模式是必学, 其实Java里边用的非常多,简直就是设计模式的活教材, 工厂方法,单例,模板方法, 装饰者,责任链都有体现。当然我会去先看一下轻松的《Head First Design》, 《设计模式》的作者之一 Eric Gamma 都大力推荐, 绝对不容错过。又过了几年, 我的IBM经理又说,现在我们默认设计模式大家都会了, 敏捷实践是必备技能 !所以, JUnit 我得会, 重构我得会, TDD,持续集成这些最最基本的敏捷实践也得知道, 要不然会被人鄙视啊。作为一个有追求的Java码农, 我写代码的时候要遵循Java 的编码规范,例如类名首字母大写, 报名要小写, 方法名要首字母小写...等等。作为代码洁癖, 我受不了脏代码, 我会不断的打磨自己的代码,直到它像一个工艺品。Java 的最佳实践 《effective java》 怎么能错过? 里边满满的全是JDK的作者们总结出来的java 编程最佳用法。不过翻译的实在是不咋滴, 很多句子都得仔细的琢磨一下才知道什么意思, 所以我打算录一系列视频讲解一下,敬请期待。【Java EE】走了这么远, 终于来到Java EE了, Java 不就是写服务器端的Web应用的吗?我会自己写个Web程序, 可以考虑把上面提到的经典的薪水支付案例改造成Web 版, 用最基础的技术Servlet/jsp/jdbc 。然后 研究struts, 自己写个简单mvc框架, 在自己的Web 程序中用起来, 这叫吃自己的狗粮。然后研究Hibenete , 自己写个简单的OR mapping框架, 再吃一次自己的狗粮。然后读一下经典的书《J2EE development without EJB》 , 对,就是spring 的作者Rod Johnson写的, 它颠覆了大家对于重量级EJB的认识, 开启了新的时代。有了这本书的铺垫, 自己写个简化的依赖注入也不是难事, 写好后还是在自己的Web程序中用起来, 最后一次吃自己的狗粮。等你做了就知道, 所有这些,都依赖Java Reflection。再往后走, 就应该是找真正的项目做, 或者去找实习了, 那是另外一个话题了,以后再聊。【阅读代码】熟读唐诗三百首,不会作诗也会吟模仿是最好的学习! 多看看大牛们的代码是怎么写的, 潜移默化,自己的武功也能提高。我身边要是有个好师傅, 跟着他,看着他编程, 提高的该有多快啊。在学习Java SE和Java EE的同时, 我会读一下这些源代码:JDK中的 Java Collection 源码 : 老祖宗的东西绝对经典JUnit 源码 : 看看Eric Gamma 和 Kent beck 是怎么通过模式来创建系统的 (回复"JUnit"查看)SpringSide : 以Spring Framework为核心的,Pragmatic风格的JavaEE应用参考示例,是JavaEE世界中的主流技术选型,最佳实践的总结与演示。国人开发的,大力推荐一下。此外我还是会研究下本世纪初著名的Jive论坛, 虽然非常古老, 虽然源码学院派十足, 但简直是设计模式的大本营, 都是活生生的应用的例子里边有个用代理模式实现权限控制, 让我记忆犹新。另外如果有余力的,有兴趣的话, 当然可以阅读Struts, Spring, hibernate的源码, 甚至参与进去开发了。如何学习Java ,这是我这么多年来的感受, 也只是我的一家之谈。 欢迎和我交流 。学习编程从来就不是一件容易的事情, 不可能看看视频,看看书就学会, 需要大量的编程和实践。 编程虽然是极为辛苦的脑力和体力劳动, 但其中蕴含的创造的乐趣也是无与伦比的。 希望每个人都能够享受这个过程,乐在其中。我有一个微信公众号,经常会分享一些Java技术相关的干货。如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
一位10年Java工作经验的架构师聊Java和工作经验
从事近十年的 JavaEE 应用开发工作,现任阿里巴巴公司系统架构师。对分布式服务架构与大数据技术有深入研究,具有丰富的 B/S 架构开发经验与项目实战经验,擅长敏捷开发模式。国内开源软件推动者之一,Smart Framework 开源框架创始人。热爱技术交流,乐于分享自己的工作经验。著有《架构探险——从零开始写Java Web框架》一书。我的十年技术之路和大家介绍下我目前所从事的工作。我目前从事分布式服务架构的设计与开发工作,在阿里的大数据平台上进行应用程序开发。我们整个系统架构采用了“前后端分离”的思想,前端关注数据展现,后端关注数据生产,通过 REST服务将前后端整合起来,所有的应用都是无状态的,可以做到水平扩展。我们将整个系统拆分成许多“微服务”,服务之间通过统一的接口来调用,每个服务是通过容器技术进行隔离,此外服务可发布到统一的服务管理平台上,可通过该平台监控每个服务的运行状态与生命周期事件,并为服务调用者提供了服务发现的能力,可对服务进行平滑升级。阿里有许多优秀的中间件与基础服务,可以快速帮助我们搭建应用系统,而且这些技术在阿里内部全是开源的,大家可以通过源码和文档学习到很多有价值的经验。阿里也提供了浓厚的技术氛围,每位同学都非常专注于自己的工作领域,大家对工作一丝不苟,相互配合,方向一致。我是如何走上技术这条路的?2006 年大学毕业,我离开了母校武汉理工大学,在院长薛胜军老师的推荐下,我来到了上海,这个对于我来说非常陌生的地方。我有幸加入了一家名为“动量软件”的创业公司,这家公司的老板曾经是亚信科技的 CTO,他也是普元软件的创始人兼 CTO,他的名字叫黄柳青,他也是薛老师的大学同学。于是就这样,我的老板成为了我的老师,我习惯叫他黄老师,包括公司其他资深的同事也成为了我的老师,因为我很想他们身上学到更多有价值的东西。刚开始工作的时候我学习了什么是云计算?什么是 SaaS、PaaS、IaaS?我们花了三年时间开发了一款名为 ODE 的 PaaS 平台,让用户可以在该平台上量身定制自己的软件,最终为客户提供基于 SaaS 的产品。确实很骄傲,那时我们已经在做云了,只是没想到后来云会在中国得到这么好的市场,可能当时只有黄老师一个人想到了吧。在 2008 年,我为公司拿回了“第一桶金”,这也是我从程序员转向项目经理的里程碑。当时我带领团队远赴深圳,为国信证券公司开发经纪人管理系统,这个项目对于我个人而言却是一笔至高无上的财富,我开始学习如何与人打交道,如何做需求分析,如何将需求转变为技术,如何带领团队小伙伴一起工作。学到了太多太多,但我依然选择在我工作第四个年头里离开了动量软件,我刚加入动量软件的时候,公司只有 5 个人(包括老板和前台),当我离开动量软件的时候,公司已经有 200 人左右了。感谢黄老师!我在他身上学到了很多,他的思想和态度直到今天都还在影响着我。我的第二份工作还是选择了我最熟悉的证券金融行业,同样也是一家创业型公司,在这家公司里我担任了技术经理,管理了整个技术团队,从项目的售前到售后,我都亲自带领团队来完成。虽然在这家公司我只做了两年,但在这短短的时间里,我学会了如何提高开发效率、如何培养技术团队、如何选拔技术人才、如何建立企业文化。但最后我发现了一个问题,越是想做好,越是很难做好,为了做成一件事情需要做很多的尝试,做事情缺乏正确并有效的方法。回想我工作的前六年时间里,我一直都是在创业公司里成长,虽然可以快速学到东西,但似乎很难学到更加规范的做事方法。于是我选择了新的工作机会,来到了 TCL 通讯,这是一家相当大的公司,公司的研发管理流程来源于法国阿里卡特公司。我在公司担任 Java 架构师职位,也算是整个 Java 团队的技术负责人,虽然团队并不是特别地大。我在这家公司做了三年,学到了如何整合现有资源、如何按标准流程去做事、如何设计系统架构、如何进行异地工作、如何跨团队工作、如何用英文来沟通。说实话,当时我没有任何的工作压力,可以按时上下班,从来都不会加班。虽然自己空闲的时间很多,但我并没有选择去浪费时间,而是开始写点技术博客,也正是因为这些技术文章,才改变了我后续的职业发展道路。我清楚的记得,那是在 2013 年 9 月 1 日,我在开源中国网站发表了我人生的第一篇博文,这篇文章影响了我后续两年。其实说句心里话,当我第一次写这篇文章时,我心里是没底的,这个框架只是根据自己的理解做出来的一个设想,当时甚至连一行代码都没写过。我的想法是先将这个思想发表出来,让大家讨论起来,我会做一个决策,然后再亲自做具体实现,最后我会将实现过程通过博文的方式展现给大家,后续大家会对我的实现进行点评,我会基于大家的建议进行改善。整个开源过程正好与敏捷的思想是一致的,有效沟通、小步快跑、拥抱变化、不断改进。也许就是我的技术文章吸引了很多广大读者,这里面不排除想邀请我加入的其它公司。我在 2014 年离开了 TCL 通讯,加入了易传媒。为什么我要放弃如此舒适的工作环境,去加入一家还在不断拼搏的企业呢?其实我看到的是未来互联网的发展趋势,广告程序化交易以及广告与大数据的结合,未来最值钱的一定是数据。抱着这样的信心,我加入了易传媒,担任系统架构师职位。当时易传媒正处于技术转型的初期,需要将 .Net 全部迁移到 Java,这件事情对于我而言是非常有挑战的。我的做法是:第一步定义开发规范与流程,第二步培养核心技术人员,第三步分阶段进行改造。仅半年时间,我们所有的产品成功地迁移到了 Java 平台,结果出乎大家的想象。公司市场也非常不错,产品得到了业界的认可,订单数源源不断,大家每天都很忙碌,但却很开心。而易传媒的“易家人”企业文化,让我所感动,不管是核心技术部门还是其它支持性部门,大家就像一家人一样,你的事情就是我的事情。直到 2015 年初,阿里巴巴与易传媒建立了合作关系,两家公司进行了深度合作,易传媒公司与阿里妈妈事业部进行了整合,新阿里妈妈从此诞生了,于是我也成为了阿里巴巴的一员,目前负责阿里妈妈大数据品牌营销产品的系统架构工作。就在两家公司整合的过程中,我完成了人生中的处女作《架构探险 —— 从零开始写 Java Web 框架》这本书,目前该书正在各大网上书店售卖,我真心希望这本书能对一些想成为架构师的程序员们有所帮助,由于我个人水平有限,又是第一次写书,写得不好的地方还请大家多多包涵。上面提到,写博客给我带来的收获颇多,那么我来分享下技术人如何写博客,又应该以怎样的态度对待。我认为技术人员写博客需要注意以下几点:思路要清晰,文章要有明确的大纲与标题。对于实战类型的文章,需要分步骤来描述。多用短句,少用长句,能一句话说明白,就不用两句话。对于不太好理解的内容,最好能打比方来说明。文章末尾需要有总结,用最精辟的语言归纳出这篇文章的主要内容。写博客首先是对自己所学知识的一个总结,此外,也为其他读者提供了很好的教程,知识得到了广播与传递。技术一条不归路,选择了这条路从未有过放弃的想法。做了十年的技术,我从来都没有放弃过它,相反,我非常热爱它,因为我一直以来都很喜欢学习,希望能学到更多的东西,这样遇到了具体的技术问题,可以随时从自己积累的知识库中找到最佳的解决方案。此外,目前我在公司虽然不怎么写代码了,但我还是会利用自己工作闲暇之余写一点开源项目或者代码框架等。工作过很多大大小小的公司,那么公司最值钱的东西是什么呢?我认为是实实在在做事情的程序员们。他们虽然工资不高,每天坐在位置上敲着代码,在很多人眼中被称为“屌丝”或“宅男”,但我认为恰恰就是这些人,他们才是公司最有价值的人。他们有自己的理想,希望能够通过自己的努力,从中得到那一点点所谓的成就感;他们需要理解产品经理真正的意图,把想法变成现实,让产品真正落地;他们更容易把握细节,而这些细节往往决定着产品的命运与成败;他们突如其来的跳槽,对我们的项目的交付有直接的影响;他们在一起工作的气氛,能体现技术公司的文化与底蕴。由此看来,对程序员的重视是相当有必要的,我们需要关心每一位程序员的职业发展,让他们在团队里能够充分地发挥出自己的能力。我们也需要对他们倍加关注,挖掘出有能力、肯吃苦、敢担当的人,给他们更多的机会,让他们成为技术领袖。互联网技术公司需要大量这样的程序员:他们是一群有着技术信仰的人,他们是一群热爱编程的人,他们是一群不解决问题睡不好觉的人;他们不是打杂的,不是外包,更不是工具;他们不喜欢被忽悠,不喜欢被冷落,更不喜欢被驱动;他们需要尊重,需要培养,更需要激情!具体说说程序员需要具备哪些素质。我个人是这样理解真正的程序员的:深爱技术,一天不写代码手就会痒,就喜欢那种成就感;为了一个问题可以废寝忘食,有时会在梦中都能写代码;代码洁癖症患者,喜欢优雅代码,写代码就像写诗一样;善于分析问题,能快速看清问题的本质,并动手解决它;喜欢研究优秀源码,学习大师的杰作,善于归纳与总结;有自己的开源项目或技术博客,喜欢学习,更喜欢分享;会关注技术圈子的新闻动态,时常会参加线下技术沙龙;知道软件开发不是一个人在战斗,更需要的是团队协作;保持良好健康的心态,用一颗积极向上的心去拥抱变化。十年的职场之路坚持不易,分享下我的「IT 职场」经验。时光飞逝,我事业中第一个十年已然结束了。在这十年里,让我收获了很多,跟大家分享一下我在 IT 职场方面的一些个人经验,不一定对每个人都实用,请大家仅作参考吧。大家既然都是做技术的,那我们不妨先从技术这个话题开始说起吧。我要与大家分享的第一点经验就是:1. 把技术当成工具技术这东西,其实一点都不神秘,它只不过是一个工具,用这个工具可以帮助我们解决实际问题,就这么简单。我们每天在面对技术,市面上也有很多技术,真的没有必要把这些技术都拿过来学习一遍,然后想办法找个场景去应用它。如果真的这样做了,那么只能说明技术不是工具,而是玩具,技术不是这样玩的。我们应该从另一个角度来看待技术,不妨从自己的实际工作环境出发,现在需要什么,我们就学什么,而不要漫无目的的追求一些新技术。当然,对于新技术还是需要有所关注的,至少需要知道这个新技术是干什么用的,而且还要善于总结,将有价值的技术收集起来,以备将来使用,当需要使用的时候再来深入研究。人的精力是有限的,人的生命也是短暂的,要善于利用自己的时间,合理地学习技术。不要把技术看得那么重要,别把它当回事儿,把它当工具就行了,它就像我们写字的笔一样,用铅笔能写字,用钢笔一样能写字。作为一名技术人员,除了学习与应用技术以外,还需要为自己做一个正确的职业规划,清晰认识自己究竟属于哪种技术人才,是技术专家类型的,还是技术管理类型的。路到底该怎么走?需要自己做出决定。在我们职业路线上,最重要的人莫过于老板(我指的老板可以是公司大老板,也可以是自己的顶头上司),对待自己的老板,我也有一些经验:2. 把老板当成情人大家应该非常清楚,情人是需要浪漫的,浪漫是需要惊喜的。老板其实跟情人一样,也是需要惊喜的。我们做下属的,要懂得找到合适的机会给老板带来惊喜。我们跟情人谈情说爱,这是一种很好的沟通方式,可别忽略了跟老板“谈情说爱”,我们需要与老板保持良好的沟通,这种沟通并不仅仅是溜须拍马。讲一个真实的故事吧。记得曾经我的一位同事,技术非常好,做东西非常快,质量也很高,同事们都觉得他是牛人,但他从来都不懂得在老板面前表现自己,老板也只是觉得他是可以做事的,但升职加薪的事情往往总是不会优先考虑他。大家很定会问:怎样在老板面前表现自己呢?其实方法有很多,由于篇幅有限,我先提供三招吧:第一招:在给老板做程序演示的时候,不要只是单纯的演示,不妨先用一个 PPT,简单表达一下自己的解决方案,然后再做演示,这样效果会好很多。老板会认为自己是花了心思的,是想把事情做得更好的。第二招:把自己每天的工作简单记录一下,每周汇总一次,以邮件的形式发送给老板,让老板知道自己每天在做什么。每月写一篇本月工作总结与下月工作计划,同样发邮件给老板。年底可以写一个年终工作总结,打印出来,悄悄地放在老板的桌子上。第三招:借汇报工作为理由,定期请老板出去吃饭,制造面对面单独沟通的机会。在谈话过程中,强调自己愿意帮助老板分担工作压力。对待老板其实很简单,只要能帮他做事,又能让他开心,他基本上就搞定了。老板搞定了,自己的职业发展才会平步青云。但千万别忽略了还有一群人,他们或许是自己的团队战友,或许是自己的竞争对手,
一位资深程序员大牛给予Java初学者的学习路线建议
Java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈每个阶段要学习的内容甚至是一些书籍。这一部分的内容,同样适用于一些希望转行到Java的同学。在大家看之前,我要先声明两点。1、由于我本人是Java后端开发出身,因此所推荐的学习内容是Java Web和Java后端开发的路线,非Java Web和Java后端开发的同学请适当参考其学习思想即可,切勿照搬。2、下面对于【第一部分】的推荐内容,目的是让你尽快成为一个可以参加工作的Java开发者,更适用于处于待业状态,准备转行Java的同学。如果你是在校学生,务必要在学好基础(比如计算机系统、算法、编译原理等等)的前提下,再考虑去进行下面的学习。第一部分:对于尚未做过Java工作的同学,包括一些在校生以及刚准备转行Java的同学。一、Java基础首先去找一个Java的基础教程学一下,这里可以推荐一个微信公众号(Java团长)你可以到这个公众号里找相应的视频教程。学习Java基础的时候,应该尽量多动手,很多时候,你想当然的事情,等你写出来运行一下,你就会发现不是这么回事儿,不信你就试试。学完以上内容以后,你应该对Java有一个基本的了解了,你可以用Java语言写出一些简单的程序,并且你用的是最简单的编辑器,比如记事本。这个时候,不要急于进入下一部分,留下几天好好写一些程序,尽可能熟悉这些基础内容。二、Web开发等你写上几天程序以后,你往往会比较迷茫,因为你写的东西似乎看起来毫无用处,比如实现一个简单的计算器,读取一个文件等。这个时候你就应该去学着写一些让你觉得有意思的东西了,所以你应该学习更多的知识。这些内容主要是Web开发相关的内容,包括HTML/CSS/JS(前端页面)、Servlet/JSP(J2EE)以及Mysql(数据库)相关的知识。它们的学习顺序应该是从前到后,因此最先学习的应该是HTML/CSS/JS(前端页面),这部分内容你可以去上面的那个runoob网站上找。你可以试着自己写一些页面,当然,你可以尽你最大的努力让它变得最漂亮。这部分内容对于后端Java来说,理论上不是特别重要,但至少要达到可以自己写出一些简单页面的水平。接下来,你需要学习的是Servlet/JSP(J2EE)部分,这部分是Java后端开发必须非常精通的部分,因此这部分是这三部分中最需要花精力的,而且这个时候,你要学会使用开发工具,而不能再使用记事本了,可以选择eclipse。当你下载安装好eclipse以后,请视频中的教程一步一步去学习,一定要多动手。关于Servlet/Jsp部分视频的选择,业界比较认可马士兵的视频,因此推荐给大家。当然了,我本人并没有看过他的视频,所以不好说的太绝对,如果大家自己有更好的选择,可以坚持自己的,不要被我干扰。最后一步,你需要学会使用数据库,mysql是个不错的入门选择,而且Java领域里主流的关系型数据库就是mysql。这部分一般在你学习Servlet/Jsp的时候,就会接触到的,其中的JDBC部分就是数据库相关的部分。你不仅要学会使用JDBC操作数据库,还要学会使用数据库客户端工具,比如navicat,sqlyog,二选一即可。三、开发框架当你学会以上内容以后,这个时候你还不足以参加工作,你还需要继续深造。公司里为了提高开发的效率,会使用一些Java Web框架,因此你还需要学习一些开发框架。目前比较主流的是SSM框架,即spring、springmvc、mybatis。你需要学会这三个框架的搭建,并用它们做出一个简单的增删改查的Web项目。你可以不理解那些配置都是什么含义,以及为什么要这么做,这些留着后面你去了解。但你一定要可以快速的利用它们三个搭建出一个Web框架,你可以记录下你第一次搭建的过程,相信我,你一定会用到的。还要提一句的是,你在搭建SSM的过程中,可能会经常接触到一个叫maven的工具。这个工具也是你以后工作当中几乎是必须要使用的工具,所以你在搭建SSM的过程中,也可以顺便了解一下maven的知识。在你目前这个阶段,你只需要在网络上了解一下maven基本的使用方法即可,一些高端的用法随着你工作经验的增加,会逐渐接触到的。四、找工作当你完成开发框架的学习以后,你就该找工作了,在校的找实习,毕业的找全职。与此同时,在找工作的同时,你不应该停下你的学习,准确的说,是你在以后都不能停下学习。上面这些内容你只是囫囵吞枣的学会了使用,你可以逐步尝试着去了解更多的东西,网络是你最重要的老师。第二部分:对于参加工作一年以内的同学。恭喜你,这个时候,你已经拥有了一份Java的工作。这个阶段是你成长极快的阶段,而且你可能会经常加班。但是加班不代表你就可以松懈了,永远记得我说的那句话,从你入行那一刻起,你就要不停的学习。在这一年里,你至少需要看完《Java编程思想》这本书。这本书的内容是帮助你对于Java有一个更加深入的了解,是Java基础的升级版。这本书很厚,当初看这本书,我花了整整三个月。正常速度的话,应该可以在半年左右看完。我这里不要求过高,只要你在一年以内把这本书看完即可。当然了,我所说的看完,是充分吸收,而不是读一遍就完事了,因此有些内容你可能会看不止一遍。总而言之,这个阶段的核心学习思想就是,在工作中实践,并且更加深入的了解Java基础。第三部分:对于参加工作1年到2年的同学。这部分时间段的同学,已经对Java有了一个更加深入的了解。但是对于面向对象的体会可能还不够深刻,编程的时候还停留在完成功能的层次,很少会去考虑设计的问题。于是这个时候,设计模式就来了。我当时看的是《大话设计模式》这本书,并且写了完整版的设计模式博客。因此,我要求大家,最多在你工作一年的时候,必须开始写博客,而设计模式就是你博客的开端。请记住,我所提的基本都是最低要求,因此不要有任何松懈的心理,否则五年后,你不要去羡慕别人高于你的工资,也不要去羡慕别人进入了某公司。这一年,你必须对于设计模式了如指掌,《大话设计模式》可以作为你的开端。此外,设计模式并不是你这一年唯一的任务,你还需要看一些关于代码编写优化的书。比如《重构 改善既有代码的设计》,《effective java》。总而言之,这个阶段,你的核心任务就是提高你的代码能力,要能写出一手优雅的代码。第四部分:对于参加工作2年到3年的同学有的同学在这个时候觉得自己已经很牛逼了,于是忍不住开始慢慢松懈。请记住,你还嫩的多。这个阶段,有一本书是你必须看的,它叫做《深入理解Java虚拟机》。这本书绝对是Java开发者最重要的书,没有之一。在我眼里,这本书的重要性还要高于《Java编程思想》。这本书的内容是帮助你全面的了解Java虚拟机,在这个阶段,你一定已经知道Java是运行在JVM之上的。所以,对于JVM,你没有任何理由不了解它。另外,在过去2年的工作当中,你肯定或多或少接触过并发。这个时候,你应该去更加深入的了解并发相关的知识,而这部分内容,我比较推荐《Java并发编程实战》这本书。只要你把这本书啃下来了,并发的部分基本已经了解了十之六七。与此同时,这个阶段你要做的事情还远不止如此。这个时候,你应该对于你所使用的框架应该有了更深入的了解,对于Java的类库也有了更深入的了解。因此,你需要去看一些JDK中的类的源码,也包括你所使用的框架的源码。这些源码能看懂的前提是,你必须对设计模式非常了解。否则的话,你看源码的过程中,永远会有这样那样的疑问,这段代码为什么要这么写?为什么要定义这个接口,它看起来好像很多余?由此也可以看出,这些学习的过程是环环相扣的,如果你任何一个阶段拉下来了,那么你就真的跟不上了,或者说是一步慢步步慢。而且我很负责的告诉你,我在这个阶段的时候,所学习的东西远多于这里所罗列出来的。因此千万不要觉得你已经学的很多了,我所说的这些都只是最低要求,不光是我,很多人在这个时间段所学习的内容都远超本文的范围。如果你不能跟上节奏的话,若干年后,如果不是程序猿市场还不错的话,你很可能不仅仅是工资比别人低,公司没别人好,而是根本就找不到工作。总而言之,这个阶段,你需要做的是深入了解Java底层和Java类库(比如并发那本书就是Java并发包java.concurrent的内容),也就是JVM和JDK的相关内容。而且还要更深入的去了解你所使用的框架,方式比较推荐看源码或者看官方文档。另外,还有一种学习的方式,在2年这个阶段,也应该启用了,那就是造轮子。不要听信那套“不要重复造轮子”的论调,那是公司为了节省时间成本编造出来的。重复造轮子或许对别人没有价值,因为你造的轮子可能早就有了,而且一般情况下你造出来的轮子还没有现存的好。但是对别人没有价值,不代表对你自己没有价值。一个造轮子的过程,是一个从无到有的过程。这个过程可以对你进行系统的锻炼,它不仅考察你的编码能力,还考察你的框架设计能力,你需要让你的轮子拥有足够好的扩展性、健壮性。而且在造轮子的过程中,你会遇到各种各样的难题,这些难题往往又是你学习的契机。当你把轮子造好的时候,你一定会发现,其实你自己收获了很多。所以,这个阶段,除了上面提到的了解JVM、JDK和框架源码以外,也请你根据别人优秀的源码,去造一个任何你能够想象出来的轮子。第五部分:参加工作3年到4年的同学这个阶段的同学,提升已经是很难了,而且这个阶段的学习往往会比较多样化。因为在前3年的过程中,你肯定或多或少接触过一些其它的技术,比如大数据、分布式缓存、分布式消息服务、分布式计算、软负载均衡等等。这些技术,你能精通任何一项,都将是你未来面试时巨大的优势,因此如果你对某一项技术感兴趣的话,这个时候可以深入去研究一下。这项技术不一定是你工作所用到的,但一定是相关的。而且在研究一门新技术时,切忌朝三暮四。有的同学今天去整整大数据,搞搞Hadoop、hbase一类的东西。过不了一段时间,就觉得没意思,又去研究分布式缓存,比如redis。然后又过不了一段时间,又去研究分布式计算,比如整整Mapreduce或者storm。结果到最后,搞得自己好像什么都会一样,在简历上大言不惭的写上大数据、分布式缓存、分布式计算都了解,其实任何一个都只是浮于表面。到时候面试官随便一问,就把你给识破了。一定要记住,作为一个程序猿,平日里所接触的技术可能会很多,但是想要让一门技术成为你的优势,那么一定是你对这门技术的了解强过绝大多数人才行。因此在这个阶段,你就不能再简单的去学习前3年的内容了,虽然前面的学习如果还不够深入的话依旧要继续,但这个时候你应该更多的考虑建立你的优势,也可以称为差异性。差异性相信不难理解,就是让你自己变得与众不同。你前面三年的学习足够你成为一名基本合格的Java开发者,但你离成为一名优秀的Java开发者还有很大的距离。所谓优秀,即能别人所不能。而你前三年所学习的内容,是很多做过几年的Java开发都能够掌握的。那么为了让自己有差异性,你就需要另辟蹊径,找一个方向深入研究下去,以期在将来,你能够成为这个领域的专家,比如分布式计算领域的专家,大数据领域的专家,并发领域的专家等等。此外,你除了建立你的差异性之外,还要去弥补你基础上的不足,直到现在,我都没有提及基础知识。原因是基础是很枯燥无味的,学的太早不仅容易懵逼,而且懵逼的同时还容易产生心理阴影,以至于以后再不想去研究这些基础。但基础又是你深入研究一些领域时所必须掌握的,比如你去研究分布式计算,你不懂算法你玩个毛毛?比如你去做分布式缓存,你对计算机系统的内存不了解,你如何去做缓存?如果你的基础本来就非常强,那么恭喜你,相信你在之前的工作中已经充分体会到了这些基础对你的帮助。但我相信大部分人的基础都很薄弱,哪怕是科班毕业的人,很多人也不敢说自己当初的基础学的多么强大,比如算法、计算机系统原理、编译原理这些。但是每个人时间都是有限的,而且这些基础的书籍每一本读下来,没个一年半载的,还真拿不下来,因此还是要有所抉择的。虽然艺多不压身,但问题是艺多是有代价的,是需要你付出时间和精力的,而我个人更赞成在同等代价的情况下获取最大的收获。首先,我比较推崇的基础书籍有三本,分别是《深入理解计算机系统》,《tcp/ip详解 卷一、二、三》,《数据结构与算法》。其中TCP/IP有三本书,但我们
Java快速排序和归并排序详解
快速排序概述快速排序算法借鉴的是二叉树前序遍历的思想,最终对数组进行排序。优点:对于数据量比较大的数组排序,由于采用的具有二叉树二分的思想,故排序速度比较快局限只适用于顺序存储结构的数据排序(数组 ,ArrayList等),不适用于链式的数据结构算法实现思路一.将目标数组转化为这样一个数组。数组中的某个位置左边的所有数据都比该位置的数据小,该位置右边的数据都比该位置数据大。实现思路:1.取出数组第0个数据  2.从数组最右边开始遍历,如果遍历位置的数据比第0个位置的数据小,将该位置的数据赋值给左边指针停留下的位置。 3.改变遍历方向,从左边开始开始遍历,如果发现左边的数据比第0个位置的数据大,将该位置的数据赋值给2步骤停留下来的位置,并变换方向。 4.循环2、3步骤直到左右遍历到的下标重合5.将取出的第0个位置的值赋值给循环结束后左右指针停留下的位置二. 借鉴前序遍历的思路,递归,最终完成排序。代码实现1 private void quickSort(int[] array, int start, int end) {2 if (start >= end) {3 return;4 }5 int key = array[start];6 int left = start;7 int right = end;8 boolean direction = true;9 L1:10 while (left < right) {11 if (direction) {12 for (int i = right; i > left; i--) {13 if (array[i] < key) {14 array[left++] = array[i];15 right = i;16 direction = !direction;17 continue L1;18 }19 }20 right = left;21 } else {22 for (int i = left; i < right; i++) {23 if (array[i] > key) {24 array[right--] = array[i];25 left = i;26 direction = !direction;27 continue L1;28 }29 }30 left = right;31 }32 }33 array[left] = key;34 quickSort(array, start, left - 1);35 quickSort(array, left + 1, end);3637 }结果测试1 @Test2 public void testQuickSort() {3 int[] array = new int[]{1, 3, 4, 10, 2, 5, 6, 9, 7, 8};4 quickSort(array, 0, array.length - 1);5 for (int i = 0; i < array.length; i++) {6 System.out.println(array[i]);7 }8 }结果打印1 12 23 34 45 56 67 78 89 910 10归并排序概述归并排序与快速排序相同,同样是借鉴二叉树的思想,时间复杂度O(n),与快速排序一样是大量数据排序的最优方式之一。思路分析归并排序是将目标数组分成左右两个数组,左右两个数组必须是有序的,然后对这两个数组合并从而实现排序。对于任意的数组都可以将所有的数据分成若干个数组,每个数组中都只有一个元素,然后两两合并。(因此,归并排序的内存开销会比快速排序多)代码实现1 private void mergeSort(int[] array, int left, int right) {2 if (left >= right) {3 return;4 }5 int mid = (left + right) >> 1;6 mergeSort(array, left, mid);7 mergeSort(array, mid + 1, right);8 merge(array, left, mid + 1, right);9 }1011 private void merge(int[] array, int left, int mid, int right) {12 int leftSize = mid - left;13 int rightSize = right - mid + 1;14 int[] leftArray = new int[leftSize];15 int[] rightArray = new int[rightSize];16 System.arraycopy(array, left, leftArray, 0, leftSize);17 System.arraycopy(array, mid, rightArray, 0, rightSize);18 int index=left;19 int leftIndex = 0;20 int rightIndex = 0;21 while (leftIndex<leftSize&&rightIndex<rightSize){22 if(leftArray[leftIndex]<rightArray[rightIndex]){23 array[index++] = leftArray[leftIndex++];24 }else {25 array[index++] = rightArray[rightIndex++];26 }27 }28 while (leftIndex<leftSize){29 array[index++] = leftArray[leftIndex++];30 }31 while (rightIndex<rightSize){32 array[index++] = rightArray[rightIndex++];33 }34 }测试代码1 @Test2 public void testMergeSort() {3 int[] array = new int[]{1, 3, 4, 10, 2, 5, 6, 9, 7, 8};4 mergeSort(array, 0, array.length - 1);5 for (int i = 0; i < array.length; i++) {6 System.out.println(array[i]);7 }8 }结果打印12345678910
各大公司Java面试题超详细总结
以下Java面试题都是本人在面试的过程中收集的,本人抱着学习的态度找了下参考答案,有不足的地方还请指正,更多精彩内容可以关注我的微信公众号:Java团长ThreadLocal(线程变量副本)Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量。采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一个副本,每个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。ThreadLocal类中维护一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值为对应线程的变量副本。ThreadLocal在Spring中发挥着巨大的作用,在管理Request作用域中的Bean、事务管理、任务调度、AOP等模块都出现了它的身影。Spring中绝大部分Bean都可以声明成Singleton作用域,采用ThreadLocal进行封装,因此有状态的Bean就能够以singleton的方式在多线程中正常工作了。友情链接:深入研究java.lang.ThreadLocal类Java内存模型:Java虚拟机规范中将Java运行时数据分为六种。1.程序计数器:是一个数据结构,用于保存当前正常执行的程序的内存地址。Java虚拟机的多线程就是通过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都需要一个独立的程序计数器,互不影响,该区域为“线程私有”。2.Java虚拟机栈:线程私有的,与线程生命周期相同,用于存储局部变量表,操作栈,方法返回值。局部变量表放着基本数据类型,还有对象的引用。3.本地方法栈:跟虚拟机栈很像,不过它是为虚拟机使用到的Native方法服务。4.Java堆:所有线程共享的一块内存区域,对象实例几乎都在这分配内存。5.方法区:各个线程共享的区域,储存虚拟机加载的类信息,常量,静态变量,编译后的代码。6.运行时常量池:代表运行时每个class文件中的常量表。包括几种常量:编译时的数字常量、方法或者域的引用。友情链接: Java中JVM虚拟机详解“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”在什么时候:1.新生代有一个Eden区和两个survivor区,首先将对象放入Eden区,如果空间不足就向其中的一个survivor区上放,如果仍然放不下就会引发一次发生在新生代的minor GC,将存活的对象放入另一个survivor区中,然后清空Eden和之前的那个survivor区的内存。在某次GC过程中,如果发现仍然又放不下的对象,就将这些对象放入老年代内存里去。2.大对象以及长期存活的对象直接进入老年区。3.当每次执行minor GC的时候应该对要晋升到老年代的对象进行分析,如果这些马上要到老年区的老年对象的大小超过了老年区的剩余大小,那么执行一次Full GC以尽可能地获得老年区的空间。对什么东西:从GC Roots搜索不到,而且经过一次标记清理之后仍没有复活的对象。做什么: 新生代:复制清理; 老年代:标记-清除和标记-压缩算法; 永久代:存放Java中的类和加载类的类加载器本身。GC Roots都有哪些: 1. 虚拟机栈中的引用的对象 2. 方法区中静态属性引用的对象,常量引用的对象 3. 本地方法栈中JNI(即一般说的Native方法)引用的对象。友情链接:Java GC的那些事(上)友情链接:Java GC的那些事(下)友情链接:CMS垃圾收集器介绍Synchronized 与Lock都是可重入锁,同一个线程再次进入同步代码的时候.可以使用自己已经获取到的锁。Synchronized是悲观锁机制,独占锁。而Locks.ReentrantLock是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。 ReentrantLock适用场景某个线程在等待一个锁的控制权的这段时间需要中断需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程,锁可以绑定多个条件。具有公平锁功能,每个到来的线程都将排队等候。友情链接: Synchronized关键字、Lock,并解释它们之间的区别StringBuffer是线程安全的,每次操作字符串,String会生成一个新的对象,而StringBuffer不会;StringBuilder是非线程安全的友情链接:String、StringBuffer与StringBuilder之间区别fail-fast:机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件happens-before:如果两个操作之间具有happens-before 关系,那么前一个操作的结果就会对后面一个操作可见。1.程序顺序规则:一个线程中的每个操作,happens- before 于该线程中的任意后续操作。2.监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。3.volatile变量规则:对一个volatile域的写,happens- before于任意后续对这个volatile域的读。4.传递性:如果A happens- before B,且B happens- before C,那么A happens- before C。5.线程启动规则:Thread对象的start()方法happens- before于此线程的每一个动作。Volatile和Synchronized四个不同点:1 粒度不同,前者针对变量 ,后者锁对象和类2 syn阻塞,volatile线程不阻塞3 syn保证三大特性,volatile不保证原子性4 syn编译器优化,volatile不优化 volatile具备两种特性:1.保证此变量对所有线程的可见性,指一条线程修改了这个变量的值,新值对于其他线程来说是可见的,但并不是多线程安全的。2.禁止指令重排序优化。Volatile如何保证内存可见性:1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。2.当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。同步:就是一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成后,依赖任务才能完成。异步:不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,只要自己任务完成了就算完成了,被依赖的任务是否完成会通知回来。(异步的特点就是通知)。 打电话和发短信来比喻同步和异步操作。阻塞:CPU停下来等一个慢的操作完成以后,才会接着完成其他的工作。非阻塞:非阻塞就是在这个慢的执行时,CPU去做其他工作,等这个慢的完成后,CPU才会接着完成后续的操作。非阻塞会造成线程切换增加,增加CPU的使用时间能不能补偿系统的切换成本需要考虑。友情链接:Java并发编程之volatile关键字解析CAS(Compare And Swap) 无锁算法: CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。友情链接:非阻塞同步算法与CAS(Compare and Swap)无锁算法线程池的作用: 在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。常用线程池:ExecutorService 是主要的实现类,其中常用的有 Executors.newSingleThreadPool(),newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()。友情链接:线程池原理友情链接:线程池原理解析类加载器工作机制:1.装载:将Java二进制代码导入jvm中,生成Class文件。2.连接:a)校验:检查载入Class文件数据的正确性 b)准备:给类的静态变量分配存储空间 c)解析:将符号引用转成直接引用3:初始化:对类的静态变量,静态方法和静态代码块执行初始化工作。双亲委派模型:类加载器收到类加载请求,首先将请求委派给父类加载器完成 用户自定义加载器->应用程序加载器->扩展类加载器->启动类加载器。友情链接:深入理解Java虚拟机笔记—双亲委派模型 友情链接:JVM类加载的那些事友情链接:JVM(1):Java 类的加载机制一致性哈希:Memcahed缓存:数据结构:key,value对使用方法:get,put等方法友情链接:hashcode(),equal()方法深入解析Redis数据结构: String—字符串(key-value 类型)Hash—字典(hashmap) Redis的哈希结构可以使你像在数据库中更新一个属性一样只修改某一项属性值List—列表 实现消息队列Set—集合 利用唯一性Sorted Set—有序集合 可以进行排序 可以实现数据持久化友情链接: Spring + Redis 实现数据的缓存java自动装箱拆箱深入剖析谈谈Java反射机制如何写一个不可变类?索引:B+,B-,全文索引Mysql的索引是一个数据结构,旨在使数据库高效的查找数据。常用的数据结构是B+Tree,每个叶子节点不但存放了索引键的相关信息还增加了指向相邻叶子节点的指针,这样就形成了带有顺序访问指针的B+Tree,做这个优化的目的是提高不同区间访问的性能。什么时候使用索引:经常出现在group by,order by和distinc关键字后面的字段经常与其他表进行连接的表,在连接字段上应该建立索引经常出现在Where子句中的字段经常出现用作查询选择的字段友情链接:MySQL:InnoDB存储引擎的B+树索引算法友情链接:MySQL索引背后的数据结构及算法原理Spring IOC (控制反转,依赖注入)Spring支持三种依赖注入方式,分别是属性(Setter方法)注入,构造注入和接口注入。在Spring中,那些组成应用的主体及由Spring IOC容器所管理的对象被称之为Bean。Spring的IOC容器通过反射的机制实例化Bean并建立Bean之间的依赖关系。简单地讲,Bean就是由Spring IOC容器初始化、装配及被管理的对象。获取Bean对象的过程,首先通过Resource加载配置文件并启动IOC容器,然后通过getBean方法获取bean对象,就可以调用他的方法。Spring Bean的作用域:Singleton:Spring IOC容器中只有一个共享的Bean实例,一般都是Singleton作用域。Prototype:每一个请求,会产生一个新的Bean实例。Request:每一次http请求会产生一个新的Bean实例。友情链接: Spring框架IOC容器和AOP解析友情链接:浅谈Spring框架注解的用法分析友情链接:关于Spring的69个面试问答——终极列表代理的共有优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。Java静态代理:代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,代理对象可以在调用目标对象相应方法前后加上其他业务处理逻辑。缺点:一个代理类只能代理一个业务类。如果业务类增加方法时,相应的代理类也要增加方法。Java动态代理:Java动态代理是写一个类实现InvocationHandler接口,重写Invoke方法,在Invoke方法可以进行增强处
Java中高级面试题整理
一.基础知识:1)集合类:List和Set比较,各自的子类比较(ArrayList,Vector,LinkedList;HashSet,TreeSet);2)HashMap的底层实现,之后会问ConcurrentHashMap的底层实现;3)如何实现HashMap顺序存储:可以参考LinkedHashMap的底层实现;4)HashTable和ConcurrentHashMap的区别;5)String,StringBuffer和StringBuilder的区别;6)Object的方法有哪些:比如有wait方法,为什么会有;7)wait和sleep的区别,必须理解;8)JVM的内存结构,JVM的算法;9)强引用,软引用和弱引用的区别;10)数组在内存中如何分配;11)用过哪些设计模式,手写一个(除单例);12)springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的;13)spring里面的aop的原理是什么;14)mybatis如何处理结果集:反射,建议看看源码;15)java的多态表现在哪里;16)接口有什么用;17)说说http,https协议;18)tcp/ip协议簇;19)osi五层网络协议;20)tcp,udp区别;21)用过哪些加密算法:对称加密,非对称加密算法;22)说说tcp三次握手,四次挥手;23)cookie和session的区别,分布式环境怎么保存用户状态;24)git,svn区别;25)请写一段栈溢出、堆溢出的代码;26)ThreadLocal可以用来共享数据吗;二.IO:1)bio,nio,aio的区别;2)nio框架:dubbo的实现原理;3)京东内部的jsf是使用的什么协议通讯:可参见dubbo的协议;三.算法:1)java中常说的堆和栈,分别是什么数据结构;另外,为什么要分为堆和栈来存储数据。2)TreeMap如何插入数据:二叉树的左旋,右旋,双旋;3)一个排序之后的数组,插入数据,可以使用什么方法?答:二分法;问:时间复杂度是多少?4)平衡二叉树的时间复杂度;5)Hash算法和二叉树算法分别什么时候用;6)图的广度优先算法和深度优先算法:详见jvm中垃圾回收实现;四.多线程相关:1)说说阻塞队列的实现:可以参考ArrayBlockingQueue的底层实现(锁和同步都行);2)进程通讯的方式:消息队列,共享内存,信号量,socket通讯等;3)用过并发包的哪些类;4)什么地方用了多线程;5)Excutors可以产生哪些线程池;6)为什么要用线程池;7)volatile关键字的用法:使多线程中的变量可见;五.数据库相关(mysql):1)msyql优化经验:2)mysql的语句优化,使用什么工具;3)mysql的索引分类:B+,hash;什么情况用什么索引;4)mysql的存储引擎有哪些,区别是什么;5)说说事务的特性和隔离级别;6)悲观锁和乐观锁的区别,怎么实现;六.mq:1)mq的原理是什么:有点大。。都可以说;2)mq如何保证实时性;3)mq的持久化是怎么做的;七.nosql相关(主要是redis):1)redis和memcache的区别;2)用redis做过什么;3)redis是如何持久化的:rdb和aof;4)redis集群如何同步;5)redis的数据添加过程是怎样的:哈希槽;6)redis的淘汰策略有哪些;7)redis有哪些数据结构;八.zookeeper:1)zookeeper是什么;2)zookeeper哪里用到;3)zookeeper的选主过程;4)zookeeper集群之间如何通讯;5)你们的zookeeper的节点加密是用的什么方式;6)分布式锁的实现过程;九.linux相关:1)linux常用的命令有哪些;2)如何获取java进程的pid;3)如何获取某个进程的网络端口号;4)如何实时打印日志;5)如何统计某个字符串行数;十.设计与思想:1)重构过代码没有?说说经验;2)一千万的用户实时排名如何实现;3)五万人并发抢票怎么实现; 我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
java面试题大纲
跳槽时时刻刻都在发生,但是我建议大家跳槽之前,先想清楚为什么要跳槽。切不可跟风,看到同事一个个都走了,自己也盲目的开始面试起来(期间也没有准备充分),到底是因为技术原因(影响自己的发展,偏移自己规划的轨迹),还是钱给少了,不受重视。准备不充分的面试,完全是浪费时间,更是对自己的不负责(如果title很高,当我没说)。今天给大家分享下chenssy在这次跳槽中整理的Java面试大纲,其中大部分都是面试过程中的面试题,可以对照这查漏补缺,当然了,这里所列的肯定不可能覆盖全部方式。项目介绍大部分情况,这是一场面试的开门题,面试官问这个问题,主要是考察你的概述能力和全局视野。有的人经常抱怨自己每天在堆业务,但没有成长。事实上,很多情况下确实在堆业务,但并不是没有成长的。并非做中间件或者技术架构才是成长,例如我们的需求分析能力,沟通协作能力,产品思维能力,抽象建模能力等都是一个非常重要的硬实力。好的,现在进入正文。1、明确项目是做什么的2、明确项目的价值。(为什么做这个项目,它解决了用户什么痛点,它带来什么价值?)3、明确项目的功能。(这个项目涉及哪些功能?)4、明确项目的技术。(这个项目用到哪些技术?)5、明确个人在项目中的位置和作用。(你在这个项目的承担角色?)6、明确项目的整体架构。7、明确项目的优缺点,如果重新设计你会如何设计。8、明确项目的亮点。(这个项目有什么亮点?)9、明确技术成长。(你通过这个项目有哪些技术成长?)Java基础1、List 和 Set 的区别2、HashSet 是如何保证不重复的3、HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安全)?4、HashMap 的扩容过程5、HashMap 1.7 与 1.8 的 区别,说明 1.8 做了哪些优化,如何优化的?6、final finally finalize7、强引用 、软引用、 弱引用、虚引用8、Java反射9、Arrays.sort 实现原理和 Collection 实现原理10、LinkedHashMap的应用11、cloneable接口实现原理12、异常分类以及处理机制13、wait和sleep的区别14、数组在内存中如何分配Java 并发1、synchronized 的实现原理以及锁优化?2、volatile 的实现原理?3、Java 的信号灯?4、synchronized 在静态方法和普通方法的区别?5、怎么实现所有线程在等待某个事件的发生才会去执行?6、CAS?CAS 有什么缺陷,如何解决?7、synchronized 和 lock 有什么区别?8、Hashtable 是怎么加锁的 ?9、HashMap 的并发问题?10、ConcurrenHashMap 介绍?1.8 中为什么要用红黑树?11、AQS12、如何检测死锁?怎么预防死锁?13、Java 内存模型?14、如何保证多线程下 i++ 结果正确?15、线程池的种类,区别和使用场景?16、分析线程池的实现原理和线程的调度过程?17、线程池如何调优,最大数目如何确认?18、ThreadLocal原理,用的时候需要注意什么?19、CountDownLatch 和 CyclicBarrier 的用法,以及相互之间的差别?20、LockSupport工具21、Condition接口及其实现原理22、Fork/Join框架的理解23、分段锁的原理,锁力度减小的思考24、八种阻塞队列以及各个阻塞队列的特性Spring1、BeanFactory 和 FactoryBean?2、Spring IOC 的理解,其初始化过程?3、BeanFactory 和 ApplicationContext?4、Spring Bean 的生命周期,如何被管理的?5、Spring Bean 的加载过程是怎样的?6、如果要你实现Spring AOP,请问怎么实现?7、如果要你实现Spring IOC,你会注意哪些问题?8、Spring 是如何管理事务的,事务管理机制?9、Spring 的不同事务传播行为有哪些,干什么用的?10、Spring 中用到了那些设计模式?11、Spring MVC 的工作原理?12、Spring 循环注入的原理?13、Spring AOP的理解,各个术语,他们是怎么相互工作的?14、Spring 如何保证 Controller 并发的安全?Netty1、BIO、NIO和AIO2、Netty 的各大组件3、Netty的线程模型4、TCP 粘包/拆包的原因及解决方法5、了解哪几种序列化协议?包括使用场景和如何去选择6、Netty的零拷贝实现7、Netty的高性能表现在哪些方面分布式相关1、Dubbo的底层实现原理和机制2、描述一个服务从发布到被消费的详细过程3、分布式系统怎么做服务治理4、接口的幂等性的概念5、消息中间件如何解决消息丢失问题6、Dubbo的服务请求失败怎么处理7、重连机制会不会造成错误8、对分布式事务的理解9、如何实现负载均衡,有哪些算法可以实现?10、Zookeeper的用途,选举的原理是什么?11、数据的垂直拆分水平拆分。12、zookeeper原理和适用场景13、zookeeper watch机制14、redis/zk节点宕机如何处理15、分布式集群下如何做到唯一序列号16、如何做一个分布式锁17、用过哪些MQ,怎么用的,和其他mq比较有什么优缺点,MQ的连接是线程安全的吗18、MQ系统的数据如何保证不丢失19、列举出你能想到的数据库分库分表策略;分库分表后,如何解决全表查询的问题20、zookeeper的选举策略21、全局ID数据库1、mysql分页有什么优化2、悲观锁、乐观锁3、组合索引,最左原则4、mysql 的表锁、行锁5、mysql 性能优化6、mysql的索引分类:B+,hash;什么情况用什么索引7、事务的特性和隔离级别缓存1、Redis用过哪些数据数据,以及Redis底层怎么实现2、Redis缓存穿透,缓存雪崩3、如何使用Redis来实现分布式锁4、Redis的并发竞争问题如何解决5、Redis持久化的几种方式,优缺点是什么,怎么实现的6、Redis的缓存失效策略7、Redis集群,高可用,原理8、Redis缓存分片9、Redis的数据淘汰策略JVM1、详细jvm内存模型2、讲讲什么情况下回出现内存溢出,内存泄漏?3、说说Java线程栈4、JVM 年轻代到年老代的晋升过程的判断条件是什么呢?5、JVM 出现 fullGC 很频繁,怎么去线上排查问题?6、类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?7、类的实例化顺序8、JVM垃圾回收机制,何时触发MinorGC等操作9、JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的10、各种回收器,各自优缺点,重点CMS、G111、各种回收算法12、OOM错误,stackoverflow错误,permgen space错误我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
100道Java基础面试题收集整理附答案
不积跬步无以至千里,这里会不断收集和更新Java基础相关的面试题,目前已收集100题。1.什么是B/S架构?什么是C/S架构B/S(Browser/Server),浏览器/服务器程序C/S(Client/Server),客户端/服务端,桌面应用程序2.你所知道网络协议有那些?HTTP:超文本传输协议FTP:文件传输协议SMPT:简单邮件协议TELNET:远程终端协议POP3:邮件读取协议3.Java都有那些开发平台?JAVA SE:主要用在客户端开发JAVA EE:主要用在web应用程序开发JAVA ME:主要用在嵌入式应用程序开发4.什么是JVM?java虚拟机包括什么?JVM:java虚拟机,运用硬件或软件手段实现的虚拟的计算机,Java虚拟机包括:寄存器,堆栈,处理器5.Java是否需要开发人员回收内存垃圾吗?大多情况下是不需要的。Java提供了一个系统级的线程来跟踪内存分配,不再使用的内存区将会自动回收6.什么是JDK?什么是JRE?JDK:java development kit:java开发工具包,是开发人员所需要安装的环境JRE:java runtime environment:java运行环境,java程序运行所需要安装的环境7.什么是数据结构?计算机保存,组织数据的方式8.Java的数据结构有那些?线性表(ArrayList)链表(LinkedList)栈(Stack)队列(Queue)图(Map)树(Tree)9.什么是OOP?面向对象编程10.什么是面向对象?世间万物都可以看成一个对象。每个物体包括动态的行为和静态的属性,这些就构成了一个对象。11.类与对象的关系?类是对象的抽象,对象是类的具体,类是对象的模板,对象是类的实例12.Java中有几种数据类型整形:byte,short,int,long浮点型:float,double字符型:char布尔型:boolean13.什么是隐式转换,什么是显式转换显示转换就是类型强转,把一个大类型的数据强制赋值给小类型的数据;隐式转换就是大范围的变量能够接受小范围的数据;隐式转换和显式转换其实就是自动类型转换和强制类型转换。14.Char类型能不能转成int类型?能不能转化成string类型,能不能转成double类型Char在java中也是比较特殊的类型,它的int值从1开始,一共有2的16次方个数据;Char<int<long<float<double;Char类型可以隐式转成int,double类型,但是不能隐式转换成string;如果char类型转成byte,short类型的时候,需要强转。15.什么是拆装箱?拆箱:把包装类型转成基本数据类型装箱:把基本数据类型转成包装类型16.Java中的包装类都是那些?byte:Byte short:Short int:Integer long:Long float:Float double:Double char:Character boolean:Boolean17.一个java类中包含那些内容?属性、方法、内部类、构造方法、代码块。18.例如: if(a+1.0=4.0),这样做好吗?不好,因为计算机在浮点型数据运算的时候,会有误差,尽量在布尔表达式中不使用浮点型数据(if,while,switch中判断条件不使用浮点型)19.那针对浮点型数据运算出现的误差的问题,你怎么解决?使用Bigdecimal类进行浮点型数据的运算20.++i与i++的区别++i:先赋值,后计算i++:先计算,后赋值21.程序的结构有那些?顺序结构选择结构循环结构22.数组实例化有几种方式?静态实例化:创建数组的时候已经指定数组中的元素,int[] a=new int[]{1,3,3}动态实例化:实例化数组的时候,只指定了数组程度,数组中所有元素都是数组类型的默认值23.Java中各种数据默认值Byte,short,int,long默认是都是0Boolean默认值是falseChar类型的默认值是’’Float与double类型的默认是0.0对象类型的默认值是null24.Java常用包有那些?Java.langJava.ioJava.sqlJava.utilJava.awtJava.netJava.math25.Java最顶级的父类是哪个?Object26.Object类常用方法有那些?EqualsHashcodetoStringwaitnotifyclonegetClass27.java中有没有指针?有指针,但是隐藏了,开发人员无法直接操作指针,由jvm来操作指针28.java中是值传递引用传递?理论上说,java都是引用传递,对于基本数据类型,传递是值的副本,而不是值本身。对于对象类型,传递是对象的引用,当在一个方法操作操作参数的时候,其实操作的是引用所指向的对象。29.假设把实例化的数组的变量当成方法参数,当方法执行的时候改变了数组内的元素,那么在方法外,数组元素有发生改变吗?改变了,因为传递是对象的引用,操作的是引用所指向的对象30.实例化数组后,能不能改变数组长度呢?不能,数组一旦实例化,它的长度就是固定的31.假设数组内有5个元素,如果对数组进行反序,该如何做?创建一个新数组,从后到前循环遍历每个元素,将取出的元素依次顺序放入新数组中32.形参与实参形参:全称为“形式参数”,是在定义方法名和方法体的时候使用的参数,用于接收调用该方法时传入的实际值;实参:全称为“实际参数”,是在调用方法时传递给该方法的实际值。33.构造方法能不能显式调用?不能构造方法当成普通方法调用,只有在创建对象的时候它才会被系统调用34.构造方法能不能重写?能不能重载?可以重写,也可以重载35.什么是方法重载?方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要它们的参数个数或者类型不同即可。在这种情况下,该方法就叫被重载了,这个过程称为方法的重载(override)36.内部类与静态内部类的区别?静态内部类相对与外部类是独立存在的,在静态内部类中无法直接访问外部类中变量、方法。如果要访问的话,必须要new一个外部类的对象,使用new出来的对象来访问。但是可以直接访问静态的变量、调用静态的方法;普通内部类作为外部类一个成员而存在,在普通内部类中可以直接访问外部类属性,调用外部类的方法。如果外部类要访问内部类的属性或者调用内部类的方法,必须要创建一个内部类的对象,使用该对象访问属性或者调用方法。如果其他的类要访问普通内部类的属性或者调用普通内部类的方法,必须要在外部类中创建一个普通内部类的对象作为一个属性,外同类可以通过该属性调用普通内部类的方法或者访问普通内部类的属性如果其他的类要访问静态内部类的属性或者调用静态内部类的方法,直接创建一个静态内部类对象即可。37.Static关键字有什么作用?Static可以修饰内部类、方法、变量、代码块Static修饰的类是静态内部类Static修饰的方法是静态方法,表示该方法属于当前类的,而不属于某个对象的,静态方法也不能被重写,可以直接使用类名来调用。在static方法中不能使用this或者super关键字。Static修饰变量是静态变量或者叫类变量,静态变量被所有实例所共享,不会依赖于对象。静态变量在内存中只有一份拷贝,在JVM加载类的时候,只为静态分配一次内存。Static修饰的代码块叫静态代码块,通常用来做程序优化的。静态代码块中的代码在整个类加载的时候只会执行一次。静态代码块可以有多个,如果有多个,按照先后顺序依次执行。38.Final在java中的作用Final可以修饰类,修饰方法,修饰变量。修饰的类叫最终类。该类不能被继承。修饰的方法不能被重写。修饰的变量叫常量,常量必须初始化,一旦初始化后,常量的值不能发生改变。39.Java中操作字符串使用哪个类?String,StringBuffer,StringBuilder40.StringBuffer,Stringbuilder有什么区别?StringBuffer与StringBuilder都继承了AbstractStringBulder类,而AbtractStringBuilder又实现了CharSequence接口,两个类都是用来进行字符串操作的。在做字符串拼接修改删除替换时,效率比string更高。StringBuffer是线程安全的,Stringbuilder是非线程安全的。所以Stringbuilder比stringbuffer效率更高,StringBuffer的方法大多都加了synchronized关键字41.String str=”aaa”,与String str=new String(“aaa”)一样吗?不一样的。因为内存分配的方式不一样。第一种,创建的”aaa”是常量,jvm都将其分配在常量池中。第二种创建的是一个对象,jvm将其值分配在堆内存中。42.String str=”aa”,String s=”bb”,String aa=aa+s;一种创建了几个对象?一共有两个引用,三个对象。因为”aa”与”bb”都是常量,常量的值不能改变,当执行字符串拼接时候,会创建一个新的常量是” aabbb”,有将其存到常量池中。43.将下java中的math类有那些常用方法?Pow():幂运算Sqrt():平方根Round():四舍五入Abs():求绝对值Random():生成一个0-1的随机数,包括0不包括144.String类的常用方法有那些?charAt:返回指定索引处的字符indexOf():返回指定字符的索引replace():字符串替换trim():去除字符串两端空白split():分割字符串,返回一个分割后的字符串数组getBytes():返回字符串的byte类型数组length():返回字符串长度toLowerCase():将字符串转成小写字母toUpperCase():将字符串转成大写字符substring():截取字符串format():格式化字符串equals():字符串比较45.判断两个对象是否相同,能使用equlas比较吗?不能。Equlas大多用来做字符串比较,要判断基本数据类型或者对象类型,需要使用==46.==与equlas有什么区别?==可以判断基本数据类型值是否相等,也可以判断两个对象指向的内存地址是否相同,也就是说判断两个对象是否是同一个对象,Equlas通常用来做字符串比较。47.如何将字符串反转?Stringbuilder或者stringbuffer的reverse方法48.面向对象的语言有那些特征?封装、继承、多态49.Java中的继承是单继承还是多继承Java中既有单继承,又有多继承。对于java类来说只能有一个父类,对于接口来说可以同时继承多个接口50.什么是重写?什么是重载?重载和重写都是java多态的表现。重载叫override,在同一个类中多态的表现。当一个类中出现了多个相同名称的方法,但参数个数和参数类型不同,方法重载与返回值无关重写叫overwrite,是字符类中多态的表现。当子类出现与父类相同的方法,那么这就是方法重写。方法重写时,子类的返回值必须与父类的一致。如果父类方法抛出一个异常,子类重写的方法抛出的异常类型不能小于父类抛出的异常类型。51.构造方法能不能重载?能不能重写?可以重载,必须重写52.如果父类只有有参构造方法,那么子类必须要重写父类的构造方法吗?必须重写53.创建一个子类对象的时候,那么父类的构造方法会执行吗?会执行。当创建一个子类对象,调用子类构造方法的时候,子类构造方法会默认调用父类的构造方法。54.什么是父类引用指向子类对象?是java多态一种特殊的表现形式。创建父类引用,让该引用指向一个子类的对象55.当父类引用指向子类对象的时候,子类重写了父类方法和属性,那么当访问属性的时候,访问是谁的属性?调用方法时,调用的是谁的方法?子类重写了父类方法和属性,访问的是父类的属性,调用的是子类的方法56.Super与this表示什么?Super表示当前类的父类对象This表示当前类的对象57.抽象的关键字是什么?Abstract58.抽象类必须要有抽象方法吗不是必须。抽象类可以没有抽象方法。59.如果一个类中有抽象方法,那么这个一定是抽象类?包含抽象方法的类一定是抽象
Java面试通关要点汇总集
这里,笔者结合自己过往的面试经验,整理了一些核心的知识清单,帮助读者更好地回顾与复习 Java 服务端核心技术。本文会以引出问题为主,后面有时间的话,笔者陆续会抽些重要的知识点进行详细的剖析与解答。敬请关注微信公众号「Java团长」,获取最新文章。基础篇基本功面向对象的特征final, finally, finalize 的区别int 和 Integer 有什么区别重载和重写的区别抽象类和接口有什么区别说说反射的用途及实现说说自定义注解的场景及实现HTTP 请求的 GET 与 POST 方式的区别session 与 cookie 区别session 分布式处理JDBC 流程MVC 设计思想equals 与 == 的区别集合List 和 Set 区别List 和 Map 区别Arraylist 与 LinkedList 区别ArrayList 与 Vector 区别HashMap 和 Hashtable 的区别HashSet 和 HashMap 区别HashMap 和 ConcurrentHashMap 的区别HashMap 的工作原理及代码实现ConcurrentHashMap 的工作原理及代码实现线程创建线程的方式及实现sleep() 、join()、yield()有什么区别说说 CountDownLatch 原理说说 CyclicBarrier 原理说说 Semaphore 原理说说 Exchanger 原理说说 CountDownLatch 与 CyclicBarrier 区别ThreadLocal 原理分析讲讲线程池的实现原理线程池的几种方式线程的生命周期锁机制说说线程安全问题volatile 实现原理synchronize 实现原理synchronized 与 lock 的区别CAS 乐观锁ABA 问题乐观锁的业务场景及实现方式核心篇数据存储MySQL 索引使用的注意事项说说反模式设计说说分库与分表设计分库与分表带来的分布式困境与应对之策说说 SQL 优化之道MySQL 遇到的死锁问题存储引擎的 InnoDB 与 MyISAM数据库索引的原理为什么要用 B-tree聚集索引与非聚集索引的区别limit 20000 加载很慢怎么解决选择合适的分布式主键方案选择合适的数据存储方案ObjectId 规则聊聊 MongoDB 使用场景倒排索引聊聊 ElasticSearch 使用场景缓存使用Redis 有哪些类型Redis 内部结构聊聊 Redis 使用场景Redis 持久化机制Redis 如何实现持久化Redis 集群方案与实现Redis 为什么是单线程的缓存奔溃缓存降级使用缓存的合理性问题消息队列消息队列的使用场景消息的重发补偿解决思路消息的幂等性解决思路消息的堆积解决思路自己如何实现消息队列如何保证消息的有序性框架篇SpringBeanFactory 和 ApplicationContext 有什么区别Spring Bean 的生命周期Spring IOC 如何实现说说 Spring AOPSpring AOP 实现原理动态代理(cglib 与 JDK)Spring 事务实现方式Spring 事务底层原理如何自定义注解实现功能Spring MVC 运行流程Spring MVC 启动流程Spring 的单例实现原理Spring 框架中用到了哪些设计模式Spring 其他产品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等)Netty为什么选择 Netty说说业务中,Netty 的使用场景原生的 NIO 在 JDK 1.7 版本存在 epoll bug什么是TCP 粘包/拆包TCP粘包/拆包的解决办法Netty 线程模型说说 Netty 的零拷贝Netty 内部执行流程Netty 重连实现微服务篇微服务前后端分离是如何做的微服务哪些框架你怎么理解 RPC 框架说说 RPC 的实现原理说说 Dubbo 的实现原理你怎么理解 RESTful说说如何设计一个良好的 API如何理解 RESTful API 的幂等性如何保证接口的幂等性说说 CAP 定理、 BASE 理论怎么考虑数据一致性问题说说最终一致性的实现方案你怎么看待微服务微服务与 SOA 的区别如何拆分服务微服务如何进行数据库管理如何应对微服务的链式调用异常对于快速追踪与定位问题微服务的安全分布式谈谈业务中使用分布式的场景Session 分布式方案分布式锁的场景分布是锁的实现方案分布式事务集群与负载均衡的算法与实现说说分库与分表设计分库与分表带来的分布式困境与应对之策安全问题安全要素与 STRIDE 威胁防范常见的 Web 攻击服务端通信安全攻防HTTPS 原理剖析HTTPS 降级攻击授权与认证基于角色的访问控制基于数据的访问控制性能优化性能指标有哪些如何发现性能瓶颈性能调优的常见手段说说你在项目中如何进行性能调优工程篇需求分析你如何对需求原型进行理解和拆分说说你对功能性需求的理解说说你对非功能性需求的理解你针对产品提出哪些交互和改进意见你如何理解用户痛点设计能力说说你在项目中使用过的 UML 图你如何考虑组件化你如何考虑服务化你如何进行领域建模你如何划分领域边界说说你项目中的领域建模说说概要设计设计模式你项目中有使用哪些设计模式说说常用开源框架中设计模式使用分析说说你对设计原则的理解23种设计模式的设计理念设计模式之间的异同,例如策略模式与状态模式的区别设计模式之间的结合,例如策略模式+简单工厂模式的实践设计模式的性能,例如单例模式哪种性能更好。业务工程你系统中的前后端分离是如何做的说说你的开发流程你和团队是如何沟通的你如何进行代码评审说说你对技术与业务的理解说说你在项目中经常遇到的 Exception说说你在项目中遇到感觉最难Bug,怎么解决的说说你在项目中遇到印象最深困难,怎么解决的你觉得你们项目还有哪些不足的地方你是否遇到过 CPU 100% ,如何排查与解决你是否遇到过 内存 OOM ,如何排查与解决说说你对敏捷开发的实践说说你对开发运维的实践介绍下工作中的一个对自己最有价值的项目,以及在这个过程中的角色软实力说说你的亮点说说你最近在看什么书说说你觉得最有意义的技术书籍工作之余做什么事情说说个人发展方向方面的思考说说你认为的服务端开发工程师应该具备哪些能力说说你认为的架构师是什么样的,架构师主要做什么说说你所理解的技术专家我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
从1.6W名面试者中收集的Java面试题精选汇总内附知识脑图
首先,声明下,以下知识点并非全部来自BAT的面试题。如果觉得在本文中笔者总结的内容能对你有所帮助,可以点赞关注一下。本文会以引出问题为主,后面有时间的话,笔者陆续会抽些重要的知识点进行详细的剖析与解答。基础篇基本功1、面向对象的特征2、final, finally, finalize 的区别3、int 和 Integer 有什么区别4、重载和重写的区别5、抽象类和接口有什么区别6、说说反射的用途及实现7、说说自定义注解的场景及实现8、HTTP 请求的 GET 与 POST 方式的区别9、session 与 cookie 区别10、session 分布式处理11、JDBC 流程12、MVC 设计思想13、equals 与 == 的区别集合1、List 和 Set 区别2、List 和 Map 区别3、Arraylist 与 LinkedList 区别4、ArrayList 与 Vector 区别5、HashMap 和 Hashtable 的区别6、HashSet 和 HashMap 区别7、HashMap 和 ConcurrentHashMap 的区别8、HashMap 的工作原理及代码实现9、ConcurrentHashMap 的工作原理及代码实现线程1、创建线程的方式及实现2、sleep() 、join()、yield()有什么区别3、说说 CountDownLatch 原理4、说说 CyclicBarrier 原理5、说说 Semaphore 原理6、说说 Exchanger 原理7、说说 CountDownLatch 与 CyclicBarrier 区别8、ThreadLocal 原理分析9、讲讲线程池的实现原理10、线程池的几种方式11、线程的生命周期锁机制1、说说线程安全问题2、volatile 实现原理3、synchronize 实现原理4、synchronized 与 lock 的区别5、CAS 乐观锁6、ABA 问题7、乐观锁的业务场景及实现方式核心篇数据存储1、MySQL 索引使用的注意事项2、说说反模式设计3、说说分库与分表设计4、分库与分表带来的分布式困境与应对之策5、说说 SQL 优化之道6、MySQL 遇到的死锁问题7、存储引擎的 InnoDB 与 MyISAM8、数据库索引的原理9、为什么要用 B-tree10、聚集索引与非聚集索引的区别11、limit 20000 加载很慢怎么解决12、选择合适的分布式主键方案13、选择合适的数据存储方案14、ObjectId 规则15、聊聊 MongoDB 使用场景16、倒排索引17、聊聊 ElasticSearch 使用场景缓存使用1、Redis 有哪些类型2、Redis 内部结构3、聊聊 Redis 使用场景4、Redis 持久化机制5、Redis 如何实现持久化6、Redis 集群方案与实现7、Redis 为什么是单线程的8、缓存奔溃9、缓存降级10、使用缓存的合理性问题消息队列1、消息队列的使用场景2、消息的重发补偿解决思路3、消息的幂等性解决思路4、消息的堆积解决思路5、自己如何实现消息队列6、如何保证消息的有序性框架篇Spring1、BeanFactory 和 ApplicationContext 有什么区别2、Spring Bean 的生命周期3、Spring IOC 如何实现4、说说 Spring AOP5、Spring AOP 实现原理6、动态代理(cglib 与 JDK)7、Spring 事务实现方式8、Spring 事务底层原理9、如何自定义注解实现功能10、Spring MVC 运行流程11、Spring MVC 启动流程12、Spring 的单例实现原理13、Spring 框架中用到了哪些设计模式14、Spring 其他产品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等)Netty1、为什么选择 Netty2、说说业务中,Netty 的使用场景3、原生的 NIO 在 JDK 1.7 版本存在 epoll bug4、什么是TCP 粘包/拆包5、TCP粘包/拆包的解决办法6、Netty 线程模型7、说说 Netty 的零拷贝8、Netty 内部执行流程9、Netty 重连实现微服务篇微服务1、前后端分离是如何做的2、微服务哪些框架3、你怎么理解 RPC 框架4、说说 RPC 的实现原理5、说说 Dubbo 的实现原理6、你怎么理解 RESTful7、说说如何设计一个良好的 API8、如何理解 RESTful API 的幂等性9、如何保证接口的幂等性10、说说 CAP 定理、 BASE 理论11、怎么考虑数据一致性问题12、说说最终一致性的实现方案13、你怎么看待微服务14、微服务与 SOA 的区别15、如何拆分服务16、微服务如何进行数据库管理17、如何应对微服务的链式调用异常18、对于快速追踪与定位问题19、微服务的安全  分布式1、谈谈业务中使用分布式的场景2、Session 分布式方案3、分布式锁的场景4、分布是锁的实现方案5、分布式事务6、集群与负载均衡的算法与实现7、说说分库与分表设计8、分库与分表带来的分布式困境与应对之策  安全&性能安全问题1、安全要素与 STRIDE 威胁2、防范常见的 Web 攻击3、服务端通信安全攻防4、HTTPS 原理剖析5、HTTPS 降级攻击6、授权与认证7、基于角色的访问控制8、基于数据的访问控制性能优化1、性能指标有哪些2、如何发现性能瓶颈3、性能调优的常见手段4、说说你在项目中如何进行性能调优  工程篇需求分析1、你如何对需求原型进行理解和拆分2、说说你对功能性需求的理解3、说说你对非功能性需求的理解4、你针对产品提出哪些交互和改进意见5、你如何理解用户痛点设计能力1、说说你在项目中使用过的 UML 图2、你如何考虑组件化3、你如何考虑服务化4、你如何进行领域建模5、你如何划分领域边界6、说说你项目中的领域建模7、说说概要设计设计模式1、你项目中有使用哪些设计模式2、说说常用开源框架中设计模式使用分析3、说说你对设计原则的理解4、23种设计模式的设计理念5、设计模式之间的异同,例如策略模式与状态模式的区别6、设计模式之间的结合,例如策略模式+简单工厂模式的实践7、设计模式的性能,例如单例模式哪种性能更好。业务工程1、你系统中的前后端分离是如何做的2、说说你的开发流程3、你和团队是如何沟通的4、你如何进行代码评审5、说说你对技术与业务的理解6、说说你在项目中经常遇到的 Exception7、说说你在项目中遇到感觉最难Bug,怎么解决的8、说说你在项目中遇到印象最深困难,怎么解决的9、你觉得你们项目还有哪些不足的地方10、你是否遇到过 CPU 100% ,如何排查与解决11、你是否遇到过 内存 OOM ,如何排查与解决12、说说你对敏捷开发的实践13、说说你对开发运维的实践14、介绍下工作中的一个对自己最有价值的项目,以及在这个过程中的角色  软实力1、说说你的亮点2、说说你最近在看什么书3、说说你觉得最有意义的技术书籍4、工作之余做什么事情5、说说个人发展方向方面的思考6、说说你认为的服务端开发工程师应该具备哪些能力7、说说你认为的架构师是什么样的,架构师主要做什么8、说说你所理解的技术专家我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
java中高级面试题整理及参考答案
面试问题:一、Java基础方面: 1、Java面相对象的思想的理解(主要是多态): http://blog.csdn.net/zhaojw_420/article/details/704776362、集合:ArrayList,LinkedList,HashMap,LinkedHashMap,ConcurrentHashMap,HashTable,HashSet的底层源码实现原理3、Java虚拟机 (1)组成以及各部分作用: http://blog.csdn.net/zhaojw_420/article/details/70477953 (2)类加载器——ClassLoader: http://blog.csdn.net/zhaojw_420/article/details/53373898 (3)类加载器的父亲委托机制深度详解: http://blog.csdn.net/zhaojw_420/article/details/53284225 (4)JVM调优: http://blog.csdn.net/zhaojw_420/article/details/70527138 (5)垃圾回收: http://blog.csdn.net/zhaojw_420/article/details/705272324、异常 http://blog.csdn.net/zhaojw_420/article/details/704777515、String,StringBuffer,StringBuilder区别 http://blog.csdn.net/zhaojw_420/article/details/704777186、值传递与引用传递: http://blog.csdn.net/zhaojw_420/article/details/704776807、Java中的equals和hashCode方法详解 http://blog.csdn.net/zhaojw_420/article/details/704777058、TCP的三次握手和四次挥手9、多线程 (1)实现线程同步: http://blog.csdn.net/zhaojw_420/article/details/67823750 (2)生产者消费者问题: http://blog.csdn.net/zhaojw_420/article/details/67826902 (3)线程安全 (4)线程死锁 (5)Synchronize实现原理 (7)happen-before规则: http://blog.csdn.net/zhaojw_420/article/details/70477874 (8)线程池 (9)DCL失效原因以及解决办法: http://blog.csdn.net/zhaojw_420/article/details/70477921 (10)线程实现方式:Thread,Runable,Callable的区别10、IO http://blog.csdn.net/zhaojw_420/article/details/7052435311、NIO http://blog.csdn.net/zhaojw_420/article/details/7052669512、网络编程13、Java内存模型 http://blog.csdn.net/zhaojw_420/article/details/70477903二、数据库(MySql) 1、面试题: http://blog.csdn.net/zhaojw_420/article/details/70530664 2、sql优化: http://blog.csdn.net/zhaojw_420/article/details/70532017 3、搜索引擎三、设计模式 单例模式,工厂模式,建造者模式,观察者模式,适配器模式,代理模式等等四、数据结构与算法: 1、链表,栈,队列,二叉树: http://blog.csdn.net/zhaojw_420/article/details/68485474 2、八大排序算法: 3、查找算法五、高并发与海量数据 1、大型网站应用之海量数据解决方案 http://blog.csdn.net/zhaojw_420/article/details/708812302、大型网站应用之高并发情况下的解决方案 http://blog.csdn.net/zhaojw_420/article/details/708812663、在一个千万级的数据库查寻中,如何提高查询效率? http://blog.csdn.net/zhaojw_420/article/details/69367682六,Struts,Spring,Hibernate,Mybatis,Springmvc七、前端:javascript,Jquery http://blog.csdn.net/zhaojw_420/article/details/70880977八、Jsp+Servlet http://blog.csdn.net/zhaojw_420/article/details/70880968九、linux操作命令(重点服务器方面操作)十、tomcat调优十一、Redis/MongoDB等NoSql http://blog.csdn.net/zhaojw_420/article/details/68066305十二、Nginx的配置与使用
金三银四跳槽季,Java面试题大纲
跳槽时时刻刻都在发生,但是我建议大家跳槽之前,先想清楚为什么要跳槽。切不可跟风,看到同事一个个都走了,自己也盲目的开始面试起来(期间也没有准备充分),到底是因为技术原因(影响自己的发展,偏移自己规划的轨迹),还是钱给少了,不受重视。准备不充分的面试,完全是浪费时间,更是对自己的不负责(如果title很高,当我没说)。今天给大家分享下我在这次跳槽中整理的Java面试大纲,其中大部分都是面试过程中的面试题,可以对照这查漏补缺,当然了,这里所列的肯定不可能覆盖全部方式。项目介绍大部分情况,这是一场面试的开门题,面试官问这个问题,主要是考察你的概述能力和全局视野。有的人经常抱怨自己每天在堆业务,但没有成长。事实上,很多情况下确实在堆业务,但并不是没有成长的。并非做中间件或者技术架构才是成长,例如我们的需求分析能力,沟通协作能力,产品思维能力,抽象建模能力等都是一个非常重要的硬实力。好的,现在进入正文。1、明确项目是做什么的2、明确项目的价值。(为什么做这个项目,它解决了用户什么痛点,它带来什么价值?)3、明确项目的功能。(这个项目涉及哪些功能?)4、明确项目的技术。(这个项目用到哪些技术?)5、明确个人在项目中的位置和作用。(你在这个项目的承担角色?)6、明确项目的整体架构。7、明确项目的优缺点,如果重新设计你会如何设计。8、明确项目的亮点。(这个项目有什么亮点?)9、明确技术成长。(你通过这个项目有哪些技术成长?)Java基础1、List 和 Set 的区别2、HashSet 是如何保证不重复的3、HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安全)?4、HashMap 的扩容过程5、HashMap 1.7 与 1.8 的 区别,说明 1.8 做了哪些优化,如何优化的?6、final finally finalize7、强引用 、软引用、 弱引用、虚引用8、Java反射9、Arrays.sort 实现原理和 Collection 实现原理10、LinkedHashMap的应用11、cloneable接口实现原理12、异常分类以及处理机制13、wait和sleep的区别14、数组在内存中如何分配Java 并发1、synchronized 的实现原理以及锁优化?2、volatile 的实现原理?3、Java 的信号灯?4、synchronized 在静态方法和普通方法的区别?5、怎么实现所有线程在等待某个事件的发生才会去执行?6、CAS?CAS 有什么缺陷,如何解决?7、synchronized 和 lock 有什么区别?8、Hashtable 是怎么加锁的 ?9、HashMap 的并发问题?10、ConcurrenHashMap 介绍?1.8 中为什么要用红黑树?11、AQS12、如何检测死锁?怎么预防死锁?13、Java 内存模型?14、如何保证多线程下 i++ 结果正确?15、线程池的种类,区别和使用场景?16、分析线程池的实现原理和线程的调度过程?17、线程池如何调优,最大数目如何确认?18、ThreadLocal原理,用的时候需要注意什么?19、CountDownLatch 和 CyclicBarrier 的用法,以及相互之间的差别?20、LockSupport工具21、Condition接口及其实现原理22、Fork/Join框架的理解23、分段锁的原理,锁力度减小的思考24、八种阻塞队列以及各个阻塞队列的特性Spring1、BeanFactory 和 FactoryBean?2、Spring IOC 的理解,其初始化过程?3、BeanFactory 和 ApplicationContext?4、Spring Bean 的生命周期,如何被管理的?5、Spring Bean 的加载过程是怎样的?6、如果要你实现Spring AOP,请问怎么实现?7、如果要你实现Spring IOC,你会注意哪些问题?8、Spring 是如何管理事务的,事务管理机制?9、Spring 的不同事务传播行为有哪些,干什么用的?10、Spring 中用到了那些设计模式?11、Spring MVC 的工作原理?12、Spring 循环注入的原理?13、Spring AOP的理解,各个术语,他们是怎么相互工作的?14、Spring 如何保证 Controller 并发的安全?Netty1、BIO、NIO和AIO2、Netty 的各大组件3、Netty的线程模型4、TCP 粘包/拆包的原因及解决方法5、了解哪几种序列化协议?包括使用场景和如何去选择6、Netty的零拷贝实现7、Netty的高性能表现在哪些方面分布式相关1、Dubbo的底层实现原理和机制2、描述一个服务从发布到被消费的详细过程3、分布式系统怎么做服务治理4、接口的幂等性的概念5、消息中间件如何解决消息丢失问题6、Dubbo的服务请求失败怎么处理7、重连机制会不会造成错误8、对分布式事务的理解9、如何实现负载均衡,有哪些算法可以实现?10、Zookeeper的用途,选举的原理是什么?11、数据的垂直拆分水平拆分。12、zookeeper原理和适用场景13、zookeeper watch机制14、redis/zk节点宕机如何处理15、分布式集群下如何做到唯一序列号16、如何做一个分布式锁17、用过哪些MQ,怎么用的,和其他mq比较有什么优缺点,MQ的连接是线程安全的吗18、MQ系统的数据如何保证不丢失19、列举出你能想到的数据库分库分表策略;分库分表后,如何解决全表查询的问题20、zookeeper的选举策略21、全局ID数据库1、mysql分页有什么优化2、悲观锁、乐观锁3、组合索引,最左原则4、mysql 的表锁、行锁5、mysql 性能优化6、mysql的索引分类:B+,hash;什么情况用什么索引7、事务的特性和隔离级别缓存1、Redis用过哪些数据数据,以及Redis底层怎么实现2、Redis缓存穿透,缓存雪崩3、如何使用Redis来实现分布式锁4、Redis的并发竞争问题如何解决5、Redis持久化的几种方式,优缺点是什么,怎么实现的6、Redis的缓存失效策略7、Redis集群,高可用,原理8、Redis缓存分片9、Redis的数据淘汰策略JVM1、详细jvm内存模型2、讲讲什么情况下回出现内存溢出,内存泄漏?3、说说Java线程栈4、JVM 年轻代到年老代的晋升过程的判断条件是什么呢?5、JVM 出现 fullGC 很频繁,怎么去线上排查问题?6、类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?7、类的实例化顺序8、JVM垃圾回收机制,何时触发MinorGC等操作9、JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的10、各种回收器,各自优缺点,重点CMS、G111、各种回收算法12、OOM错误,stackoverflow错误,permgen space错误我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
Java面试题收集以及参考答案100道
不积跬步无以至千里,这里会不断收集和更新Java基础相关的面试题,目前已收集100题。1.什么是B/S架构?什么是C/S架构B/S(Browser/Server),浏览器/服务器程序C/S(Client/Server),客户端/服务端,桌面应用程序2.你所知道网络协议有那些?HTTP:超文本传输协议FTP:文件传输协议SMPT:简单邮件协议TELNET:远程终端协议POP3:邮件读取协议3.Java都有那些开发平台?JAVA SE:主要用在客户端开发JAVA EE:主要用在web应用程序开发JAVA ME:主要用在嵌入式应用程序开发4.什么是JVM?java虚拟机包括什么?JVM:java虚拟机,运用硬件或软件手段实现的虚拟的计算机,Java虚拟机包括:寄存器,堆栈,处理器5.Java是否需要开发人员回收内存垃圾吗?大多情况下是不需要的。Java提供了一个系统级的线程来跟踪内存分配,不再使用的内存区将会自动回收6.什么是JDK?什么是JRE?JDK:java development kit:java开发工具包,是开发人员所需要安装的环境JRE:java runtime environment:java运行环境,java程序运行所需要安装的环境7.什么是数据结构?计算机保存,组织数据的方式8.Java的数据结构有那些?线性表(ArrayList)链表(LinkedList)栈(Stack)队列(Queue)图(Map)树(Tree)9.什么是OOP?面向对象编程10.什么是面向对象?世间万物都可以看成一个对象。每个物体包括动态的行为和静态的属性,这些就构成了一个对象。11.类与对象的关系?类是对象的抽象,对象是类的具体,类是对象的模板,对象是类的实例12.Java中有几种数据类型整形:byte,short,int,long浮点型:float,double字符型:char布尔型:boolean13.什么是隐式转换,什么是显式转换显示转换就是类型强转,把一个大类型的数据强制赋值给小类型的数据;隐式转换就是大范围的变量能够接受小范围的数据;隐式转换和显式转换其实就是自动类型转换和强制类型转换。14.Char类型能不能转成int类型?能不能转化成string类型,能不能转成double类型Char在java中也是比较特殊的类型,它的int值从1开始,一共有2的16次方个数据;Char<int<long<float<double;Char类型可以隐式转成int,double类型,但是不能隐式转换成string;如果char类型转成byte,short类型的时候,需要强转。15.什么是拆装箱?拆箱:把包装类型转成基本数据类型装箱:把基本数据类型转成包装类型16.Java中的包装类都是那些?byte:Byteshort:Shortint:Integerlong:Longfloat:Floatdouble:Doublechar:Characterboolean:Boolean17.一个java类中包含那些内容?属性、方法、内部类、构造方法、代码块。18.例如: if(a+1.0=4.0),这样做好吗?不好,因为计算机在浮点型数据运算的时候,会有误差,尽量在布尔表达式中不使用浮点型数据(if,while,switch中判断条件不使用浮点型)19.那针对浮点型数据运算出现的误差的问题,你怎么解决?使用Bigdecimal类进行浮点型数据的运算20.++i与i++的区别++i:先赋值,后计算i++:先计算,后赋值21.程序的结构有那些?顺序结构选择结构循环结构22.数组实例化有几种方式?静态实例化:创建数组的时候已经指定数组中的元素,int[] a=new int[]{1,3,3}动态实例化:实例化数组的时候,只指定了数组程度,数组中所有元素都是数组类型的默认值23.Java中各种数据默认值Byte,short,int,long默认是都是0Boolean默认值是falseChar类型的默认值是’’Float与double类型的默认是0.0对象类型的默认值是null24.Java常用包有那些?Java.langJava.ioJava.sqlJava.utilJava.awtJava.netJava.math25.Java最顶级的父类是哪个?Object26.Object类常用方法有那些?EqualsHashcodetoStringwaitnotifyclonegetClass27.java中有没有指针?有指针,但是隐藏了,开发人员无法直接操作指针,由jvm来操作指针28.java中是值传递引用传递?理论上说,java都是引用传递,对于基本数据类型,传递是值的副本,而不是值本身。对于对象类型,传递是对象的引用,当在一个方法操作操作参数的时候,其实操作的是引用所指向的对象。29.假设把实例化的数组的变量当成方法参数,当方法执行的时候改变了数组内的元素,那么在方法外,数组元素有发生改变吗?改变了,因为传递是对象的引用,操作的是引用所指向的对象30.实例化数组后,能不能改变数组长度呢?不能,数组一旦实例化,它的长度就是固定的31.假设数组内有5个元素,如果对数组进行反序,该如何做?创建一个新数组,从后到前循环遍历每个元素,将取出的元素依次顺序放入新数组中32.形参与实参形参:全称为“形式参数”,是在定义方法名和方法体的时候使用的参数,用于接收调用该方法时传入的实际值;实参:全称为“实际参数”,是在调用方法时传递给该方法的实际值。33.构造方法能不能显式调用?不能构造方法当成普通方法调用,只有在创建对象的时候它才会被系统调用34.构造方法能不能重写?能不能重载?可以重写,也可以重载35.什么是方法重载?方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要它们的参数个数或者类型不同即可。在这种情况下,该方法就叫被重载了,这个过程称为方法的重载(override)36.内部类与静态内部类的区别?静态内部类相对与外部类是独立存在的,在静态内部类中无法直接访问外部类中变量、方法。如果要访问的话,必须要new一个外部类的对象,使用new出来的对象来访问。但是可以直接访问静态的变量、调用静态的方法;普通内部类作为外部类一个成员而存在,在普通内部类中可以直接访问外部类属性,调用外部类的方法。如果外部类要访问内部类的属性或者调用内部类的方法,必须要创建一个内部类的对象,使用该对象访问属性或者调用方法。如果其他的类要访问普通内部类的属性或者调用普通内部类的方法,必须要在外部类中创建一个普通内部类的对象作为一个属性,外同类可以通过该属性调用普通内部类的方法或者访问普通内部类的属性如果其他的类要访问静态内部类的属性或者调用静态内部类的方法,直接创建一个静态内部类对象即可。37.Static关键字有什么作用?Static可以修饰内部类、方法、变量、代码块Static修饰的类是静态内部类Static修饰的方法是静态方法,表示该方法属于当前类的,而不属于某个对象的,静态方法也不能被重写,可以直接使用类名来调用。在static方法中不能使用this或者super关键字。Static修饰变量是静态变量或者叫类变量,静态变量被所有实例所共享,不会依赖于对象。静态变量在内存中只有一份拷贝,在JVM加载类的时候,只为静态分配一次内存。Static修饰的代码块叫静态代码块,通常用来做程序优化的。静态代码块中的代码在整个类加载的时候只会执行一次。静态代码块可以有多个,如果有多个,按照先后顺序依次执行。38.Final在java中的作用Final可以修饰类,修饰方法,修饰变量。修饰的类叫最终类。该类不能被继承。修饰的方法不能被重写。修饰的变量叫常量,常量必须初始化,一旦初始化后,常量的值不能发生改变。39.Java中操作字符串使用哪个类?String,StringBuffer,StringBuilder40.StringBuffer,Stringbuilder有什么区别?StringBuffer与StringBuilder都继承了AbstractStringBulder类,而AbtractStringBuilder又实现了CharSequence接口,两个类都是用来进行字符串操作的。在做字符串拼接修改删除替换时,效率比string更高。StringBuffer是线程安全的,Stringbuilder是非线程安全的。所以Stringbuilder比stringbuffer效率更高,StringBuffer的方法大多都加了synchronized关键字41.String str=”aaa”,与String str=new String(“aaa”)一样吗?不一样的。因为内存分配的方式不一样。第一种,创建的”aaa”是常量,jvm都将其分配在常量池中。第二种创建的是一个对象,jvm将其值分配在堆内存中。42.String str=”aa”,String s=”bb”,String aa=aa+s;一种创建了几个对象?一共有两个引用,三个对象。因为”aa”与”bb”都是常量,常量的值不能改变,当执行字符串拼接时候,会创建一个新的常量是” aabbb”,有将其存到常量池中。43.将下java中的math类有那些常用方法?Pow():幂运算Sqrt():平方根Round():四舍五入Abs():求绝对值Random():生成一个0-1的随机数,包括0不包括144.String类的常用方法有那些?charAt:返回指定索引处的字符indexOf():返回指定字符的索引replace():字符串替换trim():去除字符串两端空白split():分割字符串,返回一个分割后的字符串数组getBytes():返回字符串的byte类型数组length():返回字符串长度toLowerCase():将字符串转成小写字母toUpperCase():将字符串转成大写字符substring():截取字符串format():格式化字符串equals():字符串比较45.判断两个对象是否相同,能使用equlas比较吗?不能。Equlas大多用来做字符串比较,要判断基本数据类型或者对象类型,需要使用==46.==与equlas有什么区别?==可以判断基本数据类型值是否相等,也可以判断两个对象指向的内存地址是否相同,也就是说判断两个对象是否是同一个对象,Equlas通常用来做字符串比较。47.如何将字符串反转?Stringbuilder或者stringbuffer的reverse方法48.面向对象的语言有那些特征?封装、继承、多态49.Java中的继承是单继承还是多继承Java中既有单继承,又有多继承。对于java类来说只能有一个父类,对于接口来说可以同时继承多个接口50.什么是重写?什么是重载?重载和重写都是java多态的表现。重载叫override,在同一个类中多态的表现。当一个类中出现了多个相同名称的方法,但参数个数和参数类型不同,方法重载与返回值无关重写叫overwrite,是字符类中多态的表现。当子类出现与父类相同的方法,那么这就是方法重写。方法重写时,子类的返回值必须与父类的一致。如果父类方法抛出一个异常,子类重写的方法抛出的异常类型不能小于父类抛出的异常类型。51.构造方法能不能重载?能不能重写?可以重载,必须重写52.如果父类只有有参构造方法,那么子类必须要重写父类的构造方法吗?必须重写53.创建一个子类对象的时候,那么父类的构造方法会执行吗?会执行。当创建一个子类对象,调用子类构造方法的时候,子类构造方法会默认调用父类的构造方法。54.什么是父类引用指向子类对象?是java多态一种特殊的表现形式。创建父类引用,让该引用指向一个子类的对象55.当父类引用指向子类对象的时候,子类重写了父类方法和属性,那么当访问属性的时候,访问是谁的属性?调用方法时,调用的是谁的方法?子类重写了父类方法和属性,访问的是父类的属性,调用的是子类的方法56.Super与this表示什么?Super表示当前类的父类对象This表示当前类的对象57.抽象的关键字是什么?Abstract58.抽象类必须要有抽象方法吗不是必须。抽象类可以没有抽象方法。59.如果一个类中有抽象方法,那么这个一定是抽象类?包含抽象方法的类一定是抽象类60.抽象类
Java面试题解构
有次一个同事让我一同去面试一个候选人,没仔细看简历,所以在问了设计模式之后就让他谈一谈对内存泄漏和垃圾回收的理解,当时候选人一下子就懵了。后来才知道,他面的是初、中级开发职位,想来估计候选人心里也在骂我吧。我自己用过各式各样的方法面试候选人,也被各式各样的方式面试过。有让拿电脑直接写代码的,有让在白板上写思路、画结构的,或者挨个知识点问问题的。面试,应该是要测试候选人「是否有做好某些事情的能力」,而不应该是「知道某些事情的能力」。虽然这两者往往是相关的,但有很大一部分问题却是对「把事情做好」没有任何帮助的。其中的一类是那些「你不用的时候只是大概知道,需要使用的时候花一分钟就可以搞清楚」的问题,就算你是一个比较好学的开发者,平时会看一些跟工作关系不是那么大的东西,并且可以搞得很清楚,但时间一长,再去问你细节,我想同样会模糊不清,甚至会出错。本文并不是面试刷题的题库。而是希望可以通过对面试的问题进行分类,帮助Java工程师在准备面试时,可以高屋建瓴,快速找到所需的知识点。同时会给出一些好的、坏的示例,希望可以帮助到一些人。面试问题的分类关于会被问到的Java方面的问题,大致可以分为以下几类:1. Hotspot VM(Runtime、GC、JIT)相关问题这些问题其实属于要了解的东西,对指导编码、问题排查、运行时逻辑的理解都有好处。但如果非要问你G1、CMS、Serial垃圾回收器各自的实现方法及其不同,除非你面的就是做JVM调优的职位,那你也是倒了霉了,解决方案只能是面试前突击巩固这方面的知识。2. JDK中特定类的使用问题如果你的工作会用到一些类,可能你会很熟悉,但老实说,还是会有很多类用了很多次,每次都要去源码里看注释的情况……有注释为毛要浪费珍贵的脑容量。有病3. JDK中特定类(或操作符、关键字)的实现问题相信很大一部分(有工作经验的)工程师的工作内容是不需要考虑这些问题的,但很多有追求的工程师都很乐意去探索这些问题,比如HashMap的实现原理,TransferQueue的算法逻辑。但是,那么多类,谁能保证全部记得很清楚,如果有,一定是来面试前背过了。4. 其他一些变态的陷阱问题各种乱花渐欲迷人眼的问题,如「重载和重写的区别」「final、finally、finalize的区别」之流,实在无力吐槽。出这些题的人估计是想要考察你的基本功,但又怀着不耐烦的心情,所以挖个坑看你怎么跳。有种你编程不用搜索引擎啊。这里换个姿势问,面试官的逼格立马就显现了。比如「JDK如何保证在try-catch-finally中的finally块一定会被执行的?」,但这就属于第3类问题了,如果回答不出来,应该引导他通过已有的知识和自己的想法去实现。5. 解决实际问题这是真正有价值的问题,可以考察人的思维及解决问题能力的问题。而且不论是业务相关,亦或是技术理论相关的,都可以问出有价值的问题。如「自己设计一个ArrayList/LinkedBlockingQueue」,「设计一个秒杀系统」,「如果碰到XXX问题,你估计是哪里出的问题」等等。6. 与Java无关的问题这种问题通常是为了考察应聘者的性格、人品、知识面、学习能力等,比如「简单描述一下HTTPS的工作流程」、「最近是否有在看书或者哪方面的知识」等。有些有套路,可以抱抱佛脚,通过刷题刷出来。其他的只能自求多福了。相关问题示例下面是一些从网上看到或者自己被问到过的一些问题,仅供参考。第一类问题1. 简单描述一下JVM的GCA:随意发挥……可以参考Java 9中的GC调优基础这是一个典型的比较有开放性的问题,面试者可以从自己了解的方面入手,如分代、运行时内存结构。如果对垃圾回收器比较了解,那更可以侃侃而谈。如果被问到了比较有针对性的问题,那就看你面试前的课补的好不好了。2. Java中有哪些多线程同步的手段这个问题也可以延伸出很多知识,synchronized的实现原理、synchronized中的锁膨胀、为什么有时候使用volatile可以带来更好的性能、悲观锁&乐观锁的概念、新一代的基于Lock的锁机制,更甚者可能会问到Java的内存模型(JMM)。第二类问题1. StringBuilder vs StringBufferA:前者是后者不加锁的版本,使用场景BlaBla……现在还有人问这个问题,只有两种可能:1. 面试官或者候选人的水平比较初级;2. 面试官一下子想不到别的好问的。2. Java8比Java7添加了什么新的特性A:Lambda、streams、接口默认方法……我要是背书背的好早学文科了。3. Java自带线程池判断线程池是否已经结束运行的方法叫什么A:isShutdown和isTerminated。4. BlockingQueue,CountDownLatch及Semeaphore的使用场景5. java.util.Date与java.sql.Date有什么区别A:继承关系不知道这个问题的意义在哪里。6. 如果要从LinkedBlockingQueue中取出头部对象,分别哪个方法会返回null、抛错、阻塞A:take - 阻塞,poll - 返回null,remove - 抛错第三类问题1. ThreadLocal的实现原理A:就是一个只有当前线程可访问的以ThreadLocal实例为Key的HashMap,其内部的Map实现和HashMap的实现差不多,这个Map的实例存储在Thread对象上,所以通过封装,能保证线程只访问自己的ThreadLocal变量。好吧,很可能面试官想听到的就是这样一句话。但ThreadLocal之所以重要其实是其背后的设计思想,它将变量从共享的和需要多线程同步的环境转移到了线程私有和不需要同步的环境内,这种思想可以用来解决很多不同的场景下的问题。但是,谁关心这些呢?2. LinkedList的实现原理A:它是一个双向列表,实现了List、Deque、Cloneable等接口老实说,Deque(双向队列)这个东西见过几次,但没用过,所以现在也说不太清楚它的特征和实际使用场景,所以也不想胡侃。3. ConcurrentHashMap的实现原理A:它是一个对写操作加了锁的HashMap,不同的是它做了二次分割,元素被存储在不同的桶里,以见效锁的数据范围,提升性能。在JDK8中对这种实现又进行了修改,JDK8中的ConcurrentHashmap基于CAS和TreeBin实现的,不需要对segment或者全局加锁,只需要对单行枷锁(hashCode相同),后边的链表是链表加红黑树。对于单个值的修改使用CAS。面试官很可能想听到的是这样,但这里重要的是分治的概念。其实完全可以让候选人尝试自己去设计一个ConcurrentHashMap,然后引导他去拆分HashMap,这样才是正道啊。4. hashcode()和equals()的关系A:根据JVM标准,equals()相等的对象,hashcode()应该永远相对,反之则不一定,详见HashMap的实现。这个问题其实挺好的,但如果只是简单的问一下,没有任何意义,仍然考的是记忆力。5. TransferQueue的算法是什么样的,它和BlockingQueue有哪些不同A:源代码里有。这么回答肯定是不好的,还是去补补课吧。如果你觉得面试官问这个太无聊,可以拿到offer后丑拒。第五类问题1. 用 wait-notify 写一段代码来解决生产者-消费者问题,更进一步,在分布式的环境下怎么解决A:哈哈哈,我们来写段代码吧……wait()和notify()都是线程间通信的方法,可以直接对线程的行为进行操作。他们的本质其实是传递生产者-消费者各自的消息,理解了这一点,那么在分布式环境下就很简单了,只要找到一个第三方的可以用来传递消息的媒介(Zookeeper、Redis、Kafka等)就可以了。2. 设计一个线程池A:可以参考Java线程池的理论与实践如果对JDK的线程池java.util.concurrent.ThreadPoolExecutor比较了解,可以把一些简单的特性放上去。如果不了解,可以直接设计一个线程数组,然后加一些业务逻辑。所谓线程池,基本也就如此。3. 设计一个IOC容器A:用反射,注解,还有IOC的理论第六类问题1. 谈谈你对C10K问题的理解A:NIO对BIO在吞吐量上的优势,可以参考从I/O模型到Netty(一)我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。