面试阿里后的总结

毕业从事java开发工作4年,被别人面试过好多次,也面试过别人,感觉人跟人的差距可以好大,
有的人工作没几年,但技术广度和深度都很够;有的人工作近10年,好多基础原理都不明白。


今年一个月内面了3次阿里天猫3个不同部门,全在首轮电面挂了,好打击,也感觉好失败,浪费了不少机会


总结了一下,技术广度是够了,但技术深度不够,但感觉还不够扎实,尤其某些技术细节了解得不够透彻


看的书够多,但都不够深入,有不少没有亲自去实践,说白了就是懒,技术人员需要不断努力学习


看技术书是比较烧脑的一个过程,技术能力不是你工作多少年决定的,而是你学了多少决定的


推荐一些书给各位


<<深入理解计算机系统>> 这本书很好啊,神器啊,值得深读
<<深入理解Java虚拟机>> 周志明 
<<数据结构和算法>> java版
<<并发编程艺术>> 阿里技术专家写的
<< 亿级流量网站架构核心技术>> 开涛哥的
<<springboot实战教程>>   快速上手
<<redis源码分析>>   
<<高性能MySQL>>
现在云技术是趋势,hadoop我觉得还是必须要学的
<<hadoop权威指南>>


下面随便写了点被面的知识点,技术要工作之后不断深究,不能偷懒。






消息队列
描述:消息队列中间件是分布式系统中重要的组件
作用:异步处理,应用解耦,流量削锋和消息通讯。
例子:注册-发送邮件
      订单系统,库存系统
      抢购-放入消息队列-异步批量处理
      日志处理


常用的:rabbitmq,rocketmq,kafaka
非主流的:redis


消息队列主要四大问题:生产失败,消息丢失,消息重复消费如何处理,消息顺序性


生产者-> 队列-> 消费者


生产失败可以重发加个3次确认机制
消息丢失可以同步持久化到硬盘,当性能会降低
消息重复客户端可以根据id自己做去重处理
比较简单有效的实现消息顺序性的方式就是单线程生产者+单线程消费者+每个消费线程对应一个单独队列, 排除消息丢失的情况,可以做到严格有序。


消息队列的投递方式可以分为push和pull2种,一种模型的某些场景下的优点,在另一些场景就可能是缺点。无论是push还是pull,都存在各种的利弊。
push的优点就是及时性,缺点就是受限于消费者的消费能力,可能造成消息的堆积,broker会不断给消费者发送不能处理的消息。
pull的优点的就是主动权掌握在消费方,可以根据自己的消息速度进行消息拉取,缺点就是消费方不知道什么时候可以获取的最新的消息,会有消息延迟和忙等。




发布和订阅
主动推,和自己拉去,先进后出,先进先出


缓存


服务端缓存,客户端缓存,广域网缓存-cdn


服务端缓存:jvm缓存,堆外缓存,分布式缓存,本地硬盘缓存,静态化
客户端缓存:浏览器缓存,app客户端缓存


jvm缓存 


分布式缓存 redis缓存


redis 3.0支持集群


高可用
快速选主策略。例如zookepper
数据分主从备份
负载均衡:负载均衡,失败重试,健康检查,动态切换
限流降级:降级预警,配置中心,断融机制,读写服务降级
隔离:冷热数据隔离,读写隔离,动静隔离
超时和重试
预测和预案


缓存雪崩
使用全局互斥锁,当缓存失效,节点从db获取数据 load进缓存,再获取
原有的失效时间基础上增加一个随机值,防止同时失效,集体穿透到数据库
缓存永远不过期,但要定时刷新
使用断容器组件hystrix,具有降级策略


key-value存储系统,数据都是缓存在内存中
Memcached区别:它支持存储的value类型相对更多
               redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件


redis3.0集群默认是3主3从,槽16384
当查找某个key不在所在节点会返回所在的节点名


提高可用性和实时性,没法实时强一致性,只保证最终一致性


持久化到硬盘,有同步和异步,看产品要求






线程


两种实现方式:继承Thread类、实现Runnable接口


wait():释放占有的对象锁,线程进入等待池,释放cpu,而其他正在等待的线程即可抢占此锁,获得锁的线程即可运行程序。
而sleep()不同的是,线程调用此方法后,会休眠一段时间,休眠期间,会暂时释放cpu,但并不释放对象锁。也就是说,在休眠期间,
其他线程依然无法进入此代码内部。休眠结束,线程重新获得cpu,执行代码。wait()和sleep()最大的不同在于wait()会释放对象锁,而sleep()不会!


notify(): 该方法会唤醒因为调用对象的wait()而等待的线程,其实就是对对象锁的唤醒,从而使得wait()的线程可以有机会获取对象锁。调用notify()后
,并不会立即释放锁,而是继续执行当前代码,直到synchronized中的代码全部执行完毕,才会释放对象锁。JVM则会在等待的线程中调度一个线程去获得对象锁
,执行代码。需要注意的是,wait()和notify()必须在synchronized代码块中调用。


newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行




synchronized 
都是可以重入互斥锁:可以支持一个线程对锁的重复获取
monitorenter和monitorexit
lock
区别:自旋锁
lock要自己加锁去锁,一定要在finally里面去锁
Synchronized锁非公平锁 lock可以设置成公平锁但这样性能较差
lock锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。


lock原理
lock它通过一个int类型的状态变量state和一个FIFO队列




volatile 去掉编译期间优化重排序,直接从主内存获取值,而不是线程工作内存








ReentrantReadWriteLock
可重入读写锁(读写锁的一个实现)两者都有lock,unlock方法。写写,写读互斥;读读不互斥。可以实现并发读的高效线程安全代码




CAS交换并且比较,java有原子类AtomicInteger
乐观锁 AtomicStampedReference 解决ABA问题


BIO NIO AIO
BIO 一个Socket链接一个线程,消耗大,同步堵塞, 类似酒店里面的包厢专厢服务员 
NIO的最重要的地方是当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程就可以搞定
NIO 一个线程或者多个处理多个Socket,同步非堵塞 ,酒店里面的大厅 服务员


AIO 异步非堵塞 操作系统主动通知应用程序,类似  酒店订餐,然后顾客先去玩,菜好了,酒点会打电话通知
当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序


同步阻塞IO:在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。JAVA传统的IO模型属于此种方式!
同步非阻塞IO:在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。
异步阻塞IO:此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成,那么为什么说是阻塞的呢?
因为此时是通过select系统调用来完成的,而select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄,从而提高系统的并发性!
 异步非阻塞IO:在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。


linux提供select/poll,进程通过将一个或多个fd传递给select或poll系统调用,阻塞在select;这样select/poll可以帮我们侦测许多fd是否就绪。但是select/poll是顺序扫描fd是否就绪,
而且支持的fd数量有限。linux还提供了一个epoll系统调用,epoll是基于事件驱动方式,而不是顺序扫描,当有fd就绪时,立即回调函数rollback;




mysql的sql优化


合理的表结构
大表查询去掉表关联
充分利用索引字段
explan 检查mysql语句




mysql


一主多从
双主多从,但只从一主插入数据,另一组备份
keepalived+VIP 虚拟ip动态切换




MyISAM 不支持事务,行级锁,还有外键索引
MyISAM Merge引擎:这种类型是MyISAM类型的一种变种。合并表是将几个相同的MyISAM表合并为一个虚表。常应用于日志和数据仓
innerDB 支持事务,行级锁,外键索引
4 memory(heap):这种类型的数据表只存在于内存中。它使用散列索引,所以数据的存取速度非常快。因为是存在于内存中,所以这种类型常应用于临时表中。
5 archive:这种类型只支持select 和 insert语句,而且不支持索引。常应用于日志记录和聚合分析方面。
速度较快




mysql 半同步复制,和异步复制




。


Mybatis:1:使用连接池,datasource,在驱动并连接的这个过程中优化并解耦  J
DBC第一步其实从效率角度来看是不合适的,因为无论什么数据库都不可能支撑随机和庞大的连接数,
而且不可避免的存在连接浪费的情况,Mybatis就封装了这些优化的方法。
2:统一sql存取到XML  如果代码写在java块中,在团队合作中很可能出现两个交叉业务的代码使用类似的sql语句,而开发人员的工作本身没有交集,
那就代表sql语句肯定是无法复用的。而且对sql的修改,就代表着对java文件的修改,需要重新编译和打包部署(比如常见的状态值更改,sql修改随着业务变化必然存在修改)。 
 mybatis将sql统一存取到xml中,就算存在业务交叉,但因为统一配置的缘故,sql在xml中一目了然,
两个跨team的程序员可以看到对方的sql,来判断自己是否需要重用。并且使用xml配置可以减少代码编译。  还有就是在java中拼写长sql太恶心了。
3:参数和结果集映射  sql的方式需要传入参数,如果存在多条件“或类型”的查询(列表查询的查询条件允许空),那就代表你必须传参进行sql拼接,就算使用xml的方式也不行。
要么每个业务独立配置xml中的sql,要么还是写入java代码中,或者以工具的方式进行自动拼接。  
Mybatis使用映射的方式,方便model管理参数,同时以解析器的方式将参数动态拼接到sql(sqlmaper里那些标签),由于是model映射,连查询结果都可以统一映射,方便取出和运算。
而且mybatis对查询结果集进行了缓存处理,使得重复查询进一步进行了优化。4:对多重复sql进行复用封装  比如模板方法,将常用sql模块化,直接调用。
比如通用的save和getID之类的,只有表名和字段名有变化。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值